READ_MEOti?L"filelist.80.1 >OwBCONTENTS.7hO`gbcpio"mYEbcpio.7'K`]Cbcpio.man KJ] This tape is Usenix Distribution Tape 80.1 and is sent to you under the Terms and Conditions set forth in the enclosed agreement. The tape contains two files. The first is in tp-format and contains: 1. This READ_ME file 2. A list of all file in Distribution 80.1 3. A file "bcpio.man" which is a manual page for [b]cpio. 3. A file "bcpio.6" 4. A file "bcpio.7". 5. A file CONTENTS.? which is license dependent. The second file is the distribution itself and consists of the subset of this distribution for which we believe you are licensed. The format is a single blocked-cpio (bcpio) file. The program bcpio.6 will read the second file on any Mini-Unix, Version 6 or PWB system with a raw, no-rewind tape device. The program bcpio.7 should be used on Version 7 systems. (A different format will be used for 32V installations.) Each line in the list of files begins with a two-character symbol for the level of Bell disclosure, as specified by the person signing the release to us. The codes are: ND No Disclosure V6 Version 6 Disclosure PT Photo-Typesetter Disclosure PW PWB/UNIX Disclosure V7 Version 7 Disclosure 32 UNIX/32V Disclosure Where the code is not immediately followed by "*", the submitter has further specified his/her belief that, other than the Bell property rights, the materials are in the public domain. Where a "*" appears, the property rights are reserved. This 80.1 distribution actually contains no files of type "PT", "PW", or"32". n signing the release to us. The codes are: ND No DiscloND 4/adi ND 4/adi/READ_ME ND 4/adi/menu.1 ND 4/adi/menu.c ND 4/adi/tcom.1 ND 4/adi/tcom.c ND 4/ecm2 ND 4/ecm2/install_notes ND 4/ecm2/kchk ND 4/ecm2/kchk.c ND 4/ecm2/keyio.c ND 4/ecm2/keyio.h ND 4/ecm2/keyio.n ND 4/ecm2/keyio.o ND 4/ecm2/note ND 4/ecm2/note.c ND 4/ecm2/note.man ND 4/ecm2/refresh ND 4/ecm2/refresh.c ND 4/ecm2/setup ND 4/ecm2/setup.c ND 4/ecm2/system_notes V6* 4/n.y.blood V6* 4/n.y.blood/man V6* 4/n.y.blood/man/concat.3 V7* 4/n.y.blood/man/convert.1 V6* 4/n.y.blood/man/equ.3 V7* 4/n.y.blood/man/news.1 V6* 4/n.y.blood/src V6* 4/n.y.blood/src/concat.c V7* 4/n.y.blood/src/convert.c V6* 4/n.y.blood/src/equ.c V7* 4/n.y.blood/src/news.c V7* 4/n.y.blood/v6-7 V7* 4/n.y.blood/v6-7/READ.ME V7* 4/n.y.blood/v6-7/stat.h V7* 4/n.y.blood/v6-7/sys1.c V7* 4/n.y.blood/v6-7/sys2.c V7* 4/n.y.blood/v6-7/sys3.c V7* 4/n.y.blood/v6-7/sysent.c V7* 4/n.y.blood/v6-7/trap.c V7* 4/n.y.blood/v6-7/user.h ND 4/nijmegen ND 4/nijmegen/contents ND 4/nijmegen/dz.4 ND 4/nijmegen/dz.c ND  4/nijmegen/fconv.1 ND 4/nijmegen/fconv.c V6 4/nijmegen/restor.8 V6 4/nijmegen/restor.c V6 4/nijmegen/rk.c V6 4/nijmegen/sda V6 4/nijmegen/sda/malloc.c V6 4/purdue V6 4/purdue/doc V6 4/purdue/src V6 4/purdue/src/apl V6 4/purdue/src/apl/C V6 4/purdue/src/apl/CC V6 4/purdue/src/apl/PRAPL V6 4/purdue/src/apl/T V6  4/purdue/src/apl/TOC V6 4/purdue/src/apl/a0.c V6 4/purdue/src/apl/a1.c V6 4/purdue/src/apl/a2.c V6 4/purdue/src/apl/a3.c V6 4/purdue/src/apl/a4.c V6 4/purdue/src/apl/a5.c V6 4/purdue/src/apl/a6.c V6 4/purdue/src/apl/a7.c V6 4/purdue/src/apl/a8.c V6 4/purdue/src/apl/a9.c V6 4/purdue/src/apl/aa.c V6 4/purdue/src/apl/ab.c V6 4/purdue/src/apl/ac.c V6 4/purdue/src/apl/ad.c V6 4/purdue/src/apl/ae.c V6 4/purdue/src/apl/af.c V6 4/purdue/src/apl/ag.c V6 4/purdue/src/apl/ah.c V6 4/purdue/src/apl/ai.c V6 4/purdue/src/apl/aj.c V6 4/purdue/src/apl/ak.c V6 4/purdue/src/apl/al.c V6  4/purdue/src/apl/an.c V6 4/purdue/src/apl/ao.c V6 4/purdue/src/apl/apl.h V6 4/purdue/src/apl/apl.y V6 4/purdue/src/apl/aplp.c V6 4/purdue/src/apl/aq.c V6 4/purdue/src/apl/aw.c V6 4/purdue/src/apl/ax.s V6 4/purdue/src/apl/az.c V6 4/purdue/src/apl/doc V6 4/purdue/src/apl/doc/C V6 4/purdue/src/apl/doc/CC V6 4/purdue/src/apl/doc/PR V6 4/purdue/src/apl/doc/PRAPL V6 4/purdue/src/apl/doc/apl.1 V6 4/purdue/src/apl/doc/apl.2 V6 4/purdue/src/apl/doc/apl.6 V6 4/purdue/src/apl/doc/apl.doc V6 4/purdue/src/apl/doc/changes V6 4/purdue/src/apl/doc/chars V6 4/purdue/src/apl/doc/debug V6  4/purdue/src/apl/doc/descrpt V6 4/purdue/src/apl/doc/gentoc V6 4/purdue/src/apl/doc/read.me V6 4/purdue/src/apl/doc/run V6 4/purdue/src/apl/doc/sys.cmds V6 4/purdue/src/apl/doc/y.tab.c V6 4/purdue/src/apl/doc/yacc.acts V6 4/purdue/src/apl/doc/yacc.tmp V6 4/purdue/src/apl/enter V6 4/purdue/src/apl/lex.c V6  4/purdue/src/apl/out V6 4/purdue/src/apl/run V6 4/purdue/src/apl/run.r V6 4/purdue/src/apl/tab.c V6 4/purdue/src/apl/wait0.s V6 4/purdue/src/apl/wait1.s V6 4/purdue/src/apl/y.tab.c V6 4/purdue/sys V6 4/purdue/sys/READ_ME V6 4/purdue/sys/dmr V6 4/purdue/sys/dmr/cr.c V6 4/purdue/sys/dmr/dh.c V6  4/purdue/sys/dmr/mem.c V6 4/purdue/sys/dmr/tc.c V6 4/purdue/sys/dmr/tm.c V6 4/purdue/sys/dmr/tty.c V6 4/purdue/sys/errlog.h V6 4/purdue/sys/ken V6 4/purdue/sys/ken/prf.c V6 4/purdue/sys/ken/prtime.s V6 4/purdue/sys/l.s V6 4/purdue/sys/m45.s V6 4/purdue/sys/param.h V6 4/purdue/sys/systm.h V6 4/purdue/sys/tty.h V7 4/pitt V7 4/pitt/11stuff V7 4/pitt/11stuff/Makefile V7 4/pitt/11stuff/compall V7 4/pitt/11stuff/data.c V7 4/pitt/11stuff/mklib V7 4/pitt/11stuff/stdio.h V7 4/pitt/780stuff V7 4/pitt/780stuff/Makefile V7 4/pitt/780stuff/data.c V7 4/pitt/780stuff/stdio.h V7 4/pitt/README V7 4/pitt/README.nrf V7 4/pitt/clrerr.c V7 4/pitt/debug.c V7  4/pitt/doscan.c V7 4/pitt/fclose.c V7 4/pitt/fdopen.c V7 4/pitt/fdopensub.c V7 4/pitt/fdup.c V7 4/pitt/fget.c V7 4/pitt/fgetc.c V7 4/pitt/fgets.c V7 4/pitt/filbuf.c V7 4/pitt/fopen.c V7 4/pitt/fopensub.c V7 4/pitt/fperror.c V7 4/pitt/fprintf.c V7 4/pitt/fput.c V7 4/pitt/fputc.c V7 4/pitt/fputs.c V7 4/pitt/freopen.c V7 4/pitt/fsalloc.c V7 4/pitt/fscratch.c V7 4/pitt/fseek.c V7 4/pitt/ftell.c V7 4/pitt/fwipe.c V7 4/pitt/gcvt.c V7 4/pitt/getchar.c V7 4/pitt/getgrent.c V7 4/pitt/getgrgid.c V7 4/pitt/getgrnam.c V7 4/pitt/getpass.c V7 4/pitt/getpw.c V7 4/pitt/getpwent.c V7 4/pitt/getpwnam.c V7 4/pitt/getpwuid.c V7 4/pitt/gets.c V7 4/pitt/makebuf.c V7 4/pitt/popen.c V7 4/pitt/printf.c V7 4/pitt/putchar.c V7 4/pitt/puts.c V7 4/pitt/rdwr.c V7 4/pitt/rew.c V7 4/pitt/scanf.c V7 4/pitt/setbuf.c V7 4/pitt/sprintf.c V7 4/pitt/stdio.c V7 4/pitt/system.c V7 4/pitt/tmpnam.c V7 4/pitt/ungetc.c V6* 4/UK V6* 4/UK/information V6* 4/UK/contents V6* 4/UK/setup_uk1 V6* 4/UK/setup_qmc V6* 4/UK/setup_kent V6* 4/UK/setup_glasgow V6* 4/UK/glasgow V6* 4/UK/glasgow/disk V6* 4/UK/glasgow/disk/disk.c V6* 4/UK/glasgow/disk/disk.h V6* 4/UK/glasgow/disk/information V6* 4/UK/glasgow/disk/rk.c V6* 4/UK/glasgow/disk/rk.h V6* 4/UK/glasgow/disk/si.c V6* 4/UK/glasgow/disk/si.h V6* 4/UK/glasgow/information V6* 4/UK/glasgow/lab V6* 4/UK/glasgow/lab/ccasld V6* 4/UK/glasgow/lab/checklabel.c V6* 4/UK/glasgow/lab/doc V6* 4/UK/glasgow/lab/doc/disklabel.5 V6* 4/UK/glasgow/lab/doc/labeldisk.8 V6* 4/UK/glasgow/lab/doc/mountfs.1 V6* 4/UK/glasgow/lab/doc/unmount.1 V6* 4/UK/glasgow/lab/doc/whatdisk.1 V6* 4/UK/glasgow/lab/information V6* 4/UK/glasgow/lab/label.h V6* 4/UK/glasgow/lab/labeldisk.c V6* 4/UK/glasgow/lab/mount.c V6* 4/UK/glasgow/lab/mountfs.c V6*  4/UK/glasgow/lab/sys3.c V6* 4/UK/glasgow/lab/unmount.c V6* 4/UK/glasgow/lab/whatdisk.c V6* 4/UK/glasgow/manmacs V6* 4/UK/glasgow/manmacs/information V6* 4/UK/glasgow/manmacs/tmac.an V6* 4/UK/glasgow/ref V6* 4/UK/glasgow/ref/beg V6* 4/UK/glasgow/ref/beg/copies V6* 4/UK/glasgow/ref/beg/part1.nroff V6* 4/UK/glasgow/ref/beg/part2.nroff V6*  4/UK/glasgow/ref/cref V6* 4/UK/glasgow/ref/cref/c.ref V6* 4/UK/glasgow/ref/ctut V6* 4/UK/glasgow/ref/ctut/c.tut V6* 4/UK/glasgow/ref/edtut V6* 4/UK/glasgow/ref/edtut/ed.tut V6* 4/UK/glasgow/ref/information V6* 4/UK/glasgow/ref/lisp V6* 4/UK/glasgow/ref/lisp/ed110.rof V6* 4/UK/glasgow/ref/lisp/l110.rof V6* 4/UK/glasgow/ref/refmacs V6*  4/UK/glasgow/ref/refmacs/tmac.s V6* 4/UK/glasgow/s1 V6* 4/UK/glasgow/s1/cptree.c V6* 4/UK/glasgow/s1/doc V6* 4/UK/glasgow/s1/doc/cptree.1 V6* 4/UK/glasgow/s1/doc/lstree.1 V6* 4/UK/glasgow/s1/doc/mkdir.1 V6* 4/UK/glasgow/s1/doc/rm.1 V6* 4/UK/glasgow/s1/doc/rmdir.1 V6* 4/UK/glasgow/s1/doc/sh.1 V6* 4/UK/glasgow/s1/doc/write.1 V6* 4/UK/glasgow/s1/information V6* 4/UK/glasgow/s1/lstree V6* 4/UK/glasgow/s1/mkdir.c V6* 4/UK/glasgow/s1/rm.c V6* 4/UK/glasgow/s1/rmdir.c V6* 4/UK/glasgow/s1/sh.c V6* 4/UK/glasgow/s1/write.c V6* 4/UK/glasgow/s8 V6* 4/UK/glasgow/s8/diskcmp.c V6* 4/UK/glasgow/s8/diskcp.c V6* 4/UK/glasgow/s8/doc V6* 4/UK/glasgow/s8/doc/diskcmp.8 V6* 4/UK/glasgow/s8/doc/diskcp.8 V6* 4/UK/glasgow/s8/doc/fastdown.8 V6* 4/UK/glasgow/s8/doc/glob.8 V6* 4/UK/glasgow/s8/doc/icheck.8 V6* 4/UK/glasgow/s8/doc/init.8 V6* 4/UK/glasgow/s8/doc/mkfs.8 V6* 4/UK/glasgow/s8/doc/newuser.8 V6* 4/UK/glasgow/s8/doc/shutdown.1 V6* 4/UK/glasgow/s8/doc/single.8 V6* 4/UK/glasgow/s8/fastdown.c V6* 4/UK/glasgow/s8/glob.c V6* 4/UK/glasgow/s8/information V6* 4/UK/glasgow/s8/init.c V6* 4/UK/glasgow/s8/killsubs.c V6* 4/UK/glasgow/s8/login.c V6* 4/UK/glasgow/s8/mkfs.c V6* 4/UK/glasgow/s8/newuser.c V6* 4/UK/glasgow/s8/rkcmp.c V6* 4/UK/glasgow/s8/rkcp.c V6* 4/UK/glasgow/s8/shutdown.c V6* 4/UK/glasgow/s8/single.c V6* 4/UK/glasgow/sem V6* 4/UK/glasgow/sem/ccasld V6* 4/UK/glasgow/sem/doc V6* 4/UK/glasgow/sem/doc/lock.3 V6* 4/UK/glasgow/sem/doc/locked.3 V6* 4/UK/glasgow/sem/doc/lockif.3 V6* 4/UK/glasgow/sem/doc/semaphores.5 V6* 4/UK/glasgow/sem/doc/semopen.3 V6* 4/UK/glasgow/sem/doc/unlock.3 V6* 4/UK/glasgow/sem/information V6* 4/UK/glasgow/sem/semphr.c V6*  4/UK/glasgow/sem/sys V6* 4/UK/glasgow/sem/sys/c.c V6* 4/UK/glasgow/sem/sys/rdwri.c V6* 4/UK/glasgow/sem/sys/sem.c V6* 4/UK/glasgow/spool V6* 4/UK/glasgow/spool/doc V6* 4/UK/glasgow/spool/doc/lp.1 V6* 4/UK/glasgow/spool/doc/lp.4 V6* 4/UK/glasgow/spool/doc/lpdaemon.8 V6* 4/UK/glasgow/spool/doc/opr.1 V6* 4/UK/glasgow/spool/doc/qstate.1 V6* 4/UK/glasgow/spool/doc/queues.5 V6* 4/UK/glasgow/spool/freesem.c V6* 4/UK/glasgow/spool/information V6* 4/UK/glasgow/spool/killpid.c V6* 4/UK/glasgow/spool/lp.c V6* 4/UK/glasgow/spool/lpdaemon.c V6* 4/UK/glasgow/spool/lpdaemon.h V6* 4/UK/glasgow/spool/opr.c V6* 4/UK/glasgow/spool/qstate.c V6* 4/UK/glasgow/spool/run V6* 4/UK/glasgow/spool/sys V6* 4/UK/glasgow/spool/sys/lp.c V6* 4/UK/glasgow/sys V6* 4/UK/glasgow/sys/conf V6* 4/UK/glasgow/sys/conf/c.c.boot V6* 4/UK/glasgow/sys/conf/c.c.si V6* 4/UK/glasgow/sys/conf/ccasld.boot V6* 4/UK/glasgow/sys/conf/ccasld.si V6* 4/UK/glasgow/sys/conf/copysys V6* 4/UK/glasgow/sys/conf/data.s V6* 4/UK/glasgow/sys/conf/l.s V6* 4/UK/glasgow/sys/conf/m40.s V6* 4/UK/glasgow/sys/recompile V6* 4/UK/glasgow/sys/run V6* 4/UK/glasgow/tty V6* 4/UK/glasgow/tty/ccasld V6* 4/UK/glasgow/tty/doc V6* 4/UK/glasgow/tty/doc/getty.8 V6* 4/UK/glasgow/tty/doc/gtty.2 V6* 4/UK/glasgow/tty/doc/stty.1 V6* 4/UK/glasgow/tty/doc/stty.2 V6* 4/UK/glasgow/tty/doc/terms.2 V6* 4/UK/glasgow/tty/doc/thisisa.1 V6* 4/UK/glasgow/tty/doc/tty.1 V6* 4/UK/glasgow/tty/doc/tty.4 V6* 4/UK/glasgow/tty/doc/ttyn.3 V6* 4/UK/glasgow/tty/getty.c V6* 4/UK/glasgow/tty/gtty.s V6* 4/UK/glasgow/tty/information V6* 4/UK/glasgow/tty/login.c V6* 4/UK/glasgow/tty/stty.c V6* 4/UK/glasgow/tty/stty.s V6* 4/UK/glasgow/tty/sys V6*  4/UK/glasgow/tty/sys/dh.c V6* 4/UK/glasgow/tty/sys/dhdm.c V6* 4/UK/glasgow/tty/sys/kl.c V6* 4/UK/glasgow/tty/sys/m40.s V6* 4/UK/glasgow/tty/sys/tty.c V6* 4/UK/glasgow/tty/sys/tty.h V6* 4/UK/glasgow/tty/sysent.c V6* 4/UK/glasgow/tty/terms.s V6* 4/UK/glasgow/tty/thisisa V6* 4/UK/glasgow/tty/ttyn.s V6* 4/UK/kent V6* 4/UK/kent/bcpl V6* 4/UK/kent/bcpl/bclib V6* 4/UK/kent/bcpl/bclib/cont.a V6* 4/UK/kent/bcpl/bclib/contents V6* 4/UK/kent/bcpl/bclib/note V6* 4/UK/kent/bcpl/buildbcpl V6* 4/UK/kent/bcpl/read.me.first V6* 4/UK/kent/bcpl/source V6* 4/UK/kent/bcpl/source/cont.a V6* 4/UK/kent/bcpl/source/contents V6* 4/UK/kent/bcpl/source/note V6* 4/UK/kent/disc.index V6* 4/UK/kent/docs V6* 4/UK/kent/docs/amend V6* 4/UK/kent/docs/amend/amend0 V6* 4/UK/kent/docs/amend/amend1 V6* 4/UK/kent/docs/amend/mhd V6* 4/UK/kent/docs/amend/run V6* 4/UK/kent/docs/cdoc V6* 4/UK/kent/docs/cdoc/cdoc0 V6* 4/UK/kent/docs/cdoc/cdoc1 V6* 4/UK/kent/docs/cdoc/cdoc2 V6* 4/UK/kent/docs/cdoc/cdoc3 V6* 4/UK/kent/docs/cdoc/trac V6* 4/UK/kent/docs/cdoc/unixlicense V6* 4/UK/kent/docs/intro0 V6* 4/UK/kent/docs/intro1 V6* 4/UK/kent/fp V6* 4/UK/kent/fp/commands V6* 4/UK/kent/fp/commands/change.liba V6* 4/UK/kent/fp/commands/floatingc V6* 4/UK/kent/fp/commands/fpsim V6* 4/UK/kent/fp/commands/new.liba V6* 4/UK/kent/fp/commands/new.libc V6* 4/UK/kent/fp/fort V6* 4/UK/kent/fp/fort/f1 V6* 4/UK/kent/fp/fort/f1/f11.s V6* 4/UK/kent/fp/fort/f1/f12.s V6* 4/UK/kent/fp/fort/f4 V6* 4/UK/kent/fp/fort/f4/f41.s V6* 4/UK/kent/fp/fort/f4/f45.s V6* 4/UK/kent/fp/fort/f4/f46.s V6* 4/UK/kent/fp/fort/fx V6* 4/UK/kent/fp/fort/fx/fx4.s V6* 4/UK/kent/fp/fort/io V6* 4/UK/kent/fp/fort/io/io4.s V6* 4/UK/kent/fp/fort/io/io6.s V6* 4/UK/kent/fp/fort/rt V6* 4/UK/kent/fp/fort/rt/cont.a V6* 4/UK/kent/fp/fort/rt/contents V6* 4/UK/kent/fp/fort/rt1 V6* 4/UK/kent/fp/fort/rt1/cont.a V6* 4/UK/kent/fp/fort/rt1/contents V6* 4/UK/kent/fp/fort/rt2 V6* 4/UK/kent/fp/fort/rt2/ctime.s V6* 4/UK/kent/fp/fort/rt2/plot.s V6* 4/UK/kent/fp/fort/rt2/rand.s V6* 4/UK/kent/fp/read.me V6* 4/UK/kent/fp/read.n V6* 4/UK/kent/fp/s1 V6* 4/UK/kent/fp/s1/fpsim.c V6* 4/UK/kent/fp/s3 V6* 4/UK/kent/fp/s3/atan.s V6* 4/UK/kent/fp/s3/e.s V6* 4/UK/kent/fp/s3/ecvt.s V6* 4/UK/kent/fp/s3/exp.s V6* 4/UK/kent/fp/s3/floor.s V6* 4/UK/kent/fp/s3/fmod.s V6* 4/UK/kent/fp/s3/fp.s V6* 4/UK/kent/fp/s3/gamma.s V6* 4/UK/kent/fp/s3/log.s V6* 4/UK/kent/fp/s3/pow.s V6* 4/UK/kent/fp/s3/sin.s V6* 4/UK/kent/fp/s3/sqrt.s V6* 4/UK/kent/fp/s3/test V6* 4/UK/kent/fp/s4 V6* 4/UK/kent/fp/s4/abs.s V6* 4/UK/kent/fp/s4/atof.s V6* 4/UK/kent/fp/s4/fabs.s V6* 4/UK/kent/fp/s4/fcrt0.s V6* 4/UK/kent/fp/s4/fltpr.s V6* 4/UK/kent/fp/s4/fmcrt0.s V6* 4/UK/kent/fp/s4/ldfps.s V6* 4/UK/kent/fp/s4/ltod.s V6* 4/UK/kent/fp/s4/trap.fcrt0.s V6*  4/UK/kent/fp/s5 V6* 4/UK/kent/fp/s5/rin.c V6* 4/UK/kent/games V6* 4/UK/kent/games/instructions V6* 4/UK/kent/games/run V6* 4/UK/kent/games/star.header V6* 4/UK/kent/games/star1.c V6* 4/UK/kent/games/star2.c V6* 4/UK/kent/games/star3.c V6* 4/UK/kent/games/star4.c V6* 4/UK/kent/games/star5.c V6*  4/UK/kent/games/star6.c V6* 4/UK/kent/games/star7.c V6* 4/UK/kent/games/star8.c V6* 4/UK/kent/iolib V6* 4/UK/kent/iolib/crew.c V6* 4/UK/kent/iolib/read.me V6* 4/UK/kent/local V6* 4/UK/kent/local/cont.a V6* 4/UK/kent/local/contents V6* 4/UK/kent/lpt V6* 4/UK/kent/lpt/lpd.c V6* 4/UK/kent/lpt/lpdexec.c V6*  4/UK/kent/lpt/lpkill.c V6* 4/UK/kent/lpt/lpq.c V6* 4/UK/kent/lpt/lpr.c V6* 4/UK/kent/macro V6* 4/UK/kent/macro/cont.a V6* 4/UK/kent/macro/contents V6* 4/UK/kent/man V6* 4/UK/kent/man/index V6* 4/UK/kent/man/index/ptxun V6* 4/UK/kent/man/index/toc168 V6* 4/UK/kent/man/index/tocrc V6*  4/UK/kent/man/index/tocx1 V6* 4/UK/kent/man/index/tocx168 V6* 4/UK/kent/man/index/tocx5 V6* 4/UK/kent/man/index/tocx6 V6* 4/UK/kent/man/index/tocx8 V6* 4/UK/kent/man/index/uncmdcr V6* 4/UK/kent/man/index/uncom V6* 4/UK/kent/man/index/unptx V6* 4/UK/kent/man/man1 V6* 4/UK/kent/man/man1/cont.a V6*  4/UK/kent/man/man1/contents V6* 4/UK/kent/man/man2 V6* 4/UK/kent/man/man2/gtty.2 V6* 4/UK/kent/man/man2/stty.2 V6* 4/UK/kent/man/man2/terms.2 V6* 4/UK/kent/man/man3 V6* 4/UK/kent/man/man3/fptrap.3 V6* 4/UK/kent/man/man4 V6* 4/UK/kent/man/man4/rx.4 V6* 4/UK/kent/man/man4/tty.4 V6* 4/UK/kent/man/man6 V6* 4/UK/kent/man/man6/startrek.6 V6* 4/UK/kent/man/man7 V6* 4/UK/kent/man/man7/ioinput.7 V6* 4/UK/kent/man/man7/iomisc.7 V6* 4/UK/kent/man/man7/iooutput.7 V6* 4/UK/kent/man/man8 V6* 4/UK/kent/man/man8/archrun.8 V6* 4/UK/kent/man/man8/errdis.8 V6* 4/UK/kent/man/man8/errlog.8 V6*  4/UK/kent/man/man8/getty.8 V6* 4/UK/kent/man/man8/icheck.8 V6* 4/UK/kent/man/man8/initdate.8 V6* 4/UK/kent/man/man8/inode.8 V6* 4/UK/kent/man/man8/lpd.8 V6* 4/UK/kent/man/man8/proc1140.8 V6* 4/UK/kent/man/man8/sa.8 V6* 4/UK/kent/mc V6* 4/UK/kent/mc/mc.doc V6* 4/UK/kent/mc/mc.y V6* 4/UK/kent/mc/mc0.c V6* 4/UK/kent/mc/mc1.c V6* 4/UK/kent/mc/mc2.c V6* 4/UK/kent/mc/mc2.s V6* 4/UK/kent/mc/mc3.c V6* 4/UK/kent/mc/mch.c V6* 4/UK/kent/mc/mch1.c V6* 4/UK/kent/mc/mg0.c V6* 4/UK/kent/mc/mg1.c V6* 4/UK/kent/mc/mg2.c V6* 4/UK/kent/mc/mg3.c V6* 4/UK/kent/mc/mg4.c V6* 4/UK/kent/mc/run V6*  4/UK/kent/mdb V6* 4/UK/kent/mdb/mdb1.c V6* 4/UK/kent/mdb/mdb2.c V6* 4/UK/kent/ml1 V6* 4/UK/kent/ml1/lowl.c V6* 4/UK/kent/ml1/ml1 V6* 4/UK/kent/ml1/ml1.6 V6* 4/UK/kent/ml1/ml1_0.s V6* 4/UK/kent/ml1/ml1_1.s V6* 4/UK/kent/ml1/ml1_2.s V6* 4/UK/kent/ml1/ml1_3.s V6* 4/UK/kent/ml1/ml1_4.s V6*  4/UK/kent/ml1/ml1_5.s V6* 4/UK/kent/ml1/ml1_6.s V6* 4/UK/kent/ml1/ml1_c V6* 4/UK/kent/ml1/ml1_m.c V6* 4/UK/kent/ml1/ml1sig.r V6* 4/UK/kent/ml1/run V6* 4/UK/kent/mods V6* 4/UK/kent/mods/cont.a V6* 4/UK/kent/mods/contents V6* 4/UK/kent/mods/ctracer V6* 4/UK/kent/mods/ctracer/tracer.c V6* 4/UK/kent/mods/em V6* 4/UK/kent/mods/em/em1.c V6* 4/UK/kent/mods/em/em2.c V6* 4/UK/kent/mods/em/emhelp V6* 4/UK/kent/mods/em/emohlp V6* 4/UK/kent/rkcopy V6* 4/UK/kent/rt11 V6* 4/UK/kent/rt11/rtclose.2 V6* 4/UK/kent/rt11/rtdelete.2 V6* 4/UK/kent/rt11/rtmount.2 V6* 4/UK/kent/rt11/rtopen.2 V6* 4/UK/kent/rt11/rtpip.1 V6* 4/UK/kent/rt11/rtpip.c V6* 4/UK/kent/rt11/rtread.2 V6* 4/UK/kent/rt11/rtumount.2 V6* 4/UK/kent/rt11/rtun.c V6* 4/UK/kent/rt11/rtwrite.2 V6* 4/UK/kent/rt11/run V6* 4/UK/kent/rx V6* 4/UK/kent/rx/absblk.c V6* 4/UK/kent/rx/rx.c V6* 4/UK/kent/rx/rxaddr.c V6* 4/UK/kent/rx/rxcopy.c V6*  4/UK/kent/rx/rxinit.c V6* 4/UK/kent/rx/rxmedia.c V6* 4/UK/kent/rx/rxrdaddr.c V6* 4/UK/kent/rx/rxsh.c V6* 4/UK/kent/ted V6* 4/UK/kent/ted/first.m11 V6* 4/UK/kent/ted/mite.n V6* 4/UK/kent/ted/oldte V6* 4/UK/kent/ted/run V6* 4/UK/kent/ted/stack.m11 V6* 4/UK/kent/ted/te.hdr V6* 4/UK/kent/ted/te1.bpl V6* 4/UK/kent/ted/te2.bpl V6* 4/UK/kent/ted/te3.bpl V6* 4/UK/kent/ted/te4.bpl V6* 4/UK/kent/ukciolib V6* 4/UK/kent/ukciolib/cont.a V6* 4/UK/kent/ukciolib/contents V6* 4/UK/kent/ukciolib/man V6* 4/UK/kent/ukciolib/man/doc.n V6* 4/UK/kent/ukciolib/man/doc0 V6* 4/UK/kent/ukciolib/run V6* 4/UK/qmc V6*  4/UK/qmc/8080asm V6* 4/UK/qmc/8080asm/8080asm.h V6* 4/UK/qmc/8080asm/asm1.c V6* 4/UK/qmc/8080asm/asm2.c V6* 4/UK/qmc/8080asm/asm3.c V6* 4/UK/qmc/8080asm/asm4.c V6* 4/UK/qmc/8080asm/asminit V6* 4/UK/qmc/bin V6* 4/UK/qmc/bin/linkr V6* 4/UK/qmc/bin/macro V6* 4/UK/qmc/docs V6* 4/UK/qmc/docs/em V6*  4/UK/qmc/docs/em/emhelp V6* 4/UK/qmc/docs/em/emhelp/commands V6* 4/UK/qmc/docs/em/emhelp/keys V6* 4/UK/qmc/docs/em/emhelp/o V6* 4/UK/qmc/docs/em/emhelp/reg V6* 4/UK/qmc/docs/em/emhelp/s V6* 4/UK/qmc/docs/em/emintro.n V6* 4/UK/qmc/docs/em/tmac.M V6* 4/UK/qmc/docs/linkhelp V6*  4/UK/qmc/docs/man0 V6* 4/UK/qmc/docs/man0/qmcbasinf V6* 4/UK/qmc/docs/man0/qmcintro V6* 4/UK/qmc/docs/man0/qmcprogs V6* 4/UK/qmc/docs/man0/qmcptx V6* 4/UK/qmc/docs/man0/qmctoc V6* 4/UK/qmc/docs/man0/qmctocrc V6* 4/UK/qmc/docs/man1 V6* 4/UK/qmc/docs/man1/cont.a V6* 4/UK/qmc/docs/man1/contents V6*  4/UK/qmc/docs/man2 V6* 4/UK/qmc/docs/man3 V6* 4/UK/qmc/docs/man3/gterm.3 V6* 4/UK/qmc/docs/man3/leave.3 V6* 4/UK/qmc/docs/man4 V6* 4/UK/qmc/docs/man4/tty.4 V6* 4/UK/qmc/docs/man5 V6* 4/UK/qmc/docs/man5/elog.5 V6* 4/UK/qmc/docs/man5/news.5 V6* 4/UK/qmc/docs/man5/protocols.5 V6* 4/UK/qmc/docs/man5/spdevices.5 V6* 4/UK/qmc/docs/man5/tty.5 V6* 4/UK/qmc/docs/man6 V6* 4/UK/qmc/docs/man6/bio.6 V6* 4/UK/qmc/docs/man6/cal.6 V6* 4/UK/qmc/docs/man6/chess.6 V6* 4/UK/qmc/docs/man6/ml1.6 V6* 4/UK/qmc/docs/man6/speak.6 V6* 4/UK/qmc/docs/man7 V6* 4/UK/qmc/docs/man7/heap.7 V6* 4/UK/qmc/docs/man7/imlac.7 V6* 4/UK/qmc/docs/man7/pop.7 V6* 4/UK/qmc/docs/man8 V6* 4/UK/qmc/docs/man8/lgn.8 V6* 4/UK/qmc/docs/man8/zap.8 V6* 4/UK/qmc/docs/mas V6* 4/UK/qmc/docs/mas/mas V6* 4/UK/qmc/docs/mc V6* 4/UK/qmc/docs/mc/mc.n V6* 4/UK/qmc/docs/temp V6* 4/UK/qmc/essex V6* 4/UK/qmc/essex/dz.c V6* 4/UK/qmc/games V6* 4/UK/qmc/games/fastermind.c V6* 4/UK/qmc/games/hang.c V6* 4/UK/qmc/games/hangman.c V6* 4/UK/qmc/games/hrace.c V6* 4/UK/qmc/games/oxo.c V6* 4/UK/qmc/games/run V6* 4/UK/qmc/heap V6* 4/UK/qmc/heap/cont.a V6* 4/UK/qmc/heap/contents V6* 4/UK/qmc/imlac V6* 4/UK/qmc/imlac/graf.c V6* 4/UK/qmc/m11 V6* 4/UK/qmc/m11/cont.a V6* 4/UK/qmc/m11/contents V6* 4/UK/qmc/mas V6* 4/UK/qmc/mas/cont.a V6* 4/UK/qmc/mas/contents V6* 4/UK/qmc/mc V6* 4/UK/qmc/mc/cont.a V6* 4/UK/qmc/mc/contents V6* 4/UK/qmc/ml1 V6* 4/UK/qmc/ml1/cont.a V6* 4/UK/qmc/ml1/contents V6* 4/UK/qmc/odb V6* 4/UK/qmc/odb/odb.doc V6* 4/UK/qmc/odb/odb0.c V6* 4/UK/qmc/odb/odb1.c V6* 4/UK/qmc/odb/odb2.c V6* 4/UK/qmc/odb/odb3.c V6* 4/UK/qmc/odb/odb4.c V6* 4/UK/qmc/odb/odb5.c V6* 4/UK/qmc/odb/odb6.c V6* 4/UK/qmc/odb/odb7.c V6* 4/UK/qmc/odb/odb8.c V6* 4/UK/qmc/odb/odb9.c V6* 4/UK/qmc/odb/odbh0.c V6* 4/UK/qmc/odb/run V6* 4/UK/qmc/pop V6* 4/UK/qmc/pop/cont.a V6* 4/UK/qmc/pop/contents V6* 4/UK/qmc/pop/doc V6* 4/UK/qmc/pop/doc/setup.n V6* 4/UK/qmc/pop/note V6* 4/UK/qmc/readme.r V6* 4/UK/qmc/s1 V6* 4/UK/qmc/s1/cont.a V6* 4/UK/qmc/s1/contents V6* 4/UK/qmc/s2 V6* 4/UK/qmc/s2/cont.a V6* 4/UK/qmc/s2/contents V6* 4/UK/qmc/s4 V6* 4/UK/qmc/s4/callby.s V6* 4/UK/qmc/s4/gterm.c V6* 4/UK/qmc/s4/gterm.o V6* 4/UK/qmc/s5 V6* 4/UK/qmc/s5/setbit.c V6* 4/UK/qmc/s5/sterm.c V6* 4/UK/qmc/s5/sterm.o V6* 4/UK/qmc/s5/terms.o V6* 4/UK/qmc/s5/terms.s V6* 4/UK/qmc/ttydriver V6*  4/UK/qmc/ttydriver/conf V6* 4/UK/qmc/ttydriver/conf/m40.s V6* 4/UK/qmc/ttydriver/dmr V6* 4/UK/qmc/ttydriver/dmr/kl.c V6* 4/UK/qmc/ttydriver/dmr/tty.c V6* 4/UK/qmc/ttydriver/ken V6* 4/UK/qmc/ttydriver/ken/sysent.c V6* 4/UK/qmc/ttydriver/proc.h V6* 4/UK/qmc/ttydriver/tty.h V6* 4/UK/qmc/ttydriver/user.h V6*  4/UK/qmc/wilbur V6* 4/UK/qmc/wilbur/build1.ucl V6* 4/UK/qmc/wilbur/build2.qmc V6* 4/UK/qmc/wilbur/build3 V6* 4/UK/qmc/wilbur/build4.bell V6* 4/UK/qmc/wilbur/build5.qmc V6* 4/UK/qmc/wilbur/build6 V6* 4/UK/qmc/wilbur/ctime.c V6* 4/UK/qmc/wilbur/dz.c V6* 4/UK/qmc/wilbur/getty.c V6* 4/UK/qmc/wilbur/m40.s V6*  4/UK/qmc/wilbur/mkconf.c V6* 4/UK/qmc/wilbur/motd V6* 4/UK/qmc/wilbur/news V6* 4/UK/qmc/wilbur/passwd V6* 4/UK/qmc/wilbur/rx.c V6* 4/UK/qmc/wilbur/tty.c ND boulder ND boulder/README ND boulder/ampex V6 boulder/ampex/cf V6 boulder/ampex/cf/doc V6 boulder/ampex/cf/doc/READ_ME V6 boulder/ampex/cf/doc/c_creat V6 boulder/ampex/cf/doc/c_creat.2 V6 boulder/ampex/cf/doc/cfs V6 boulder/ampex/cf/doc/cfs.2 V6 boulder/ampex/cf/doc/df V6 boulder/ampex/cf/doc/df.2 V6 boulder/ampex/cf/doc/mkcfs V6 boulder/ampex/cf/doc/mkcfs.2 V6 boulder/ampex/cf/doc/mount V6 boulder/ampex/cf/doc/mount.2 V6 boulder/ampex/cf/doc/stat V6 boulder/ampex/cf/doc/stat.2 V6 boulder/ampex/cf/doc/tmac.book V6 boulder/ampex/cf/doc/zerosb V6 boulder/ampex/cf/doc/zerosb.2 V6 boulder/ampex/cf/kernel V6 boulder/ampex/cf/kernel/cf.h V6 boulder/ampex/cf/kernel/cf_alloc.c V6 boulder/ampex/cf/kernel/cf_creat.c V6 boulder/ampex/cf/kernel/filsys.h V6 boulder/ampex/cf/kernel/fio.c V6 boulder/ampex/cf/kernel/iget.c V6 boulder/ampex/cf/kernel/inode.h V6  boulder/ampex/cf/kernel/inout.c V6 boulder/ampex/cf/kernel/max.c V6 boulder/ampex/cf/kernel/mul.s V6 boulder/ampex/cf/kernel/newk.c V6 boulder/ampex/cf/kernel/rdwri.c V6 boulder/ampex/cf/kernel/sys2.c V6 boulder/ampex/cf/kernel/sysent.c V6 boulder/ampex/cf/kernel/trunc.c V6 boulder/ampex/cf/user V6 boulder/ampex/cf/user/ccheck.c V6 boulder/ampex/cf/user/cf.h V6 boulder/ampex/cf/user/chsb.c V6 boulder/ampex/cf/user/lni.c V6 boulder/ampex/cf/user/mkcfs.c V6 boulder/ampex/cf/user/param.h V6 boulder/ampex/cf/user/printblk.c V6 boulder/ampex/cf/user/printbn.c V6 boulder/ampex/cf/user/printi.c V6 boulder/ampex/cf/user/printsb.c V6 boulder/ampex/cf/user/zerosb.c ND boulder/ampex/clock.c ND boulder/ampex/dict ND boulder/ampex/dict/nwords ND boulder/ampex/doc ND boulder/ampex/doc/stdplt ND boulder/ampex/man ND boulder/ampex/man/mp.1 ND boulder/ampex/man/mp.4 ND boulder/ampex/man/rplot.5 ND boulder/ampex/man/tek.1 V7 boulder/ampex/man/tty.4 ND boulder/ampex/man/vplot.5 ND boulder/ampex/man/vplotdb.1 ND boulder/ampex/mkdirs ND boulder/ampex/needs ND boulder/ampex/needs.n ND boulder/ampex/scanargs ND boulder/ampex/scanargs/scanargs.3 ND boulder/ampex/scanargs/scanargs.3.v6 ND boulder/ampex/scanargs/scanargs.c ND boulder/ampex/scanargs/scanargs.c.v6 ND boulder/ampex/scanargs/scanargs.o ND boulder/ampex/stdplt ND boulder/ampex/stdplt/README ND boulder/ampex/stdplt/_cat.c ND boulder/ampex/stdplt/_cfname.c ND boulder/ampex/stdplt/_clip.c ND  boulder/ampex/stdplt/_domove.c ND boulder/ampex/stdplt/_draw.c ND boulder/ampex/stdplt/_err.c ND boulder/ampex/stdplt/_find.c ND boulder/ampex/stdplt/_fmatch.c ND boulder/ampex/stdplt/_inv2.c ND boulder/ampex/stdplt/_move.c ND boulder/ampex/stdplt/_origin.c ND boulder/ampex/stdplt/_path.c ND boulder/ampex/stdplt/_rotate.c ND boulder/ampex/stdplt/_scale.c ND boulder/ampex/stdplt/_window.c ND boulder/ampex/stdplt/_xhair.c ND boulder/ampex/stdplt/axis.c ND boulder/ampex/stdplt/base.c ND boulder/ampex/stdplt/cfont.c ND boulder/ampex/stdplt/crotate.c ND boulder/ampex/stdplt/cwidth.c ND boulder/ampex/stdplt/dash.c ND boulder/ampex/stdplt/data.c ND boulder/ampex/stdplt/display.c ND boulder/ampex/stdplt/dispts.c ND boulder/ampex/stdplt/dodisp.c ND  boulder/ampex/stdplt/domin.c ND boulder/ampex/stdplt/donice.c ND boulder/ampex/stdplt/erase.c ND boulder/ampex/stdplt/erasea.c ND boulder/ampex/stdplt/eval.c ND boulder/ampex/stdplt/fat.c ND boulder/ampex/stdplt/fgrid.c ND boulder/ampex/stdplt/frame.c ND boulder/ampex/stdplt/fwhere.c ND boulder/ampex/stdplt/graph.c ND boulder/ampex/stdplt/graph.h ND boulder/ampex/stdplt/graph.y ND boulder/ampex/stdplt/grid.c ND boulder/ampex/stdplt/libP.a ND boulder/ampex/stdplt/makelib ND boulder/ampex/stdplt/minmax.c ND boulder/ampex/stdplt/misc.c ND boulder/ampex/stdplt/pair.c ND boulder/ampex/stdplt/prframe.c ND boulder/ampex/stdplt/purge.c ND boulder/ampex/stdplt/rmframe.c ND boulder/ampex/stdplt/saxis.c ND boulder/ampex/stdplt/stdplt.h ND boulder/ampex/stdplt/textf.c ND boulder/ampex/stdplt/tst ND boulder/ampex/stdplt/tst/angle ND boulder/ampex/stdplt/tst/angle.c ND boulder/ampex/stdplt/tst/box ND boulder/ampex/stdplt/tst/box.c ND boulder/ampex/stdplt/tst/cangle ND boulder/ampex/stdplt/tst/cangle.c ND boulder/ampex/stdplt/tst/draw.c ND boulder/ampex/stdplt/tst/it ND boulder/ampex/stdplt/tst/it.c ND boulder/ampex/stdplt/tst/test ND boulder/ampex/stdplt/tst/test.c ND boulder/ampex/stdplt/tst/tstrnd.c ND boulder/ampex/stdplt/tst/tstxh ND boulder/ampex/stdplt/tst/tstxh.c ND boulder/ampex/stdplt/tst/tstxhair ND boulder/ampex/stdplt/tst/tstxhair.c ND boulder/ampex/stdplt/tst/txt ND boulder/ampex/stdplt/tst/txt.c ND boulder/ampex/stdplt/tst/vugraph1.c ND boulder/ampex/stdplt/tst/vugraph2.c ND boulder/ampex/stdplt/where.c ND boulder/ampex/stdplt/xdist.c ND boulder/ampex/stdplt/xhair.c ND boulder/ampex/stdplt/y.tab.c ND boulder/ampex/stdplt/ydist.c ND boulder/ampex/stdplt/zinit.c ND boulder/ampex/sys V7 boulder/ampex/sys/dev V7 boulder/ampex/sys/dev/dh.c V7 boulder/ampex/sys/dev/dz.c V7 boulder/ampex/sys/dev/kl.c ND boulder/ampex/sys/dev/mp.c ND boulder/ampex/sys/dev/mpl.c V7 boulder/ampex/sys/dev/tty.c V7 boulder/ampex/sys/h ND boulder/ampex/sys/h/mp.h V7 boulder/ampex/sys/h/tty.h V7 boulder/ampex/tar ND boulder/ampex/vplot ND boulder/ampex/vplot/asciichar ND boulder/ampex/vplot/chars.h ND boulder/ampex/vplot/chtst ND boulder/ampex/vplot/chtst.c ND boulder/ampex/vplot/greekchar ND boulder/ampex/vplot/mp ND boulder/ampex/vplot/mp.c ND boulder/ampex/vplot/putsym.h ND boulder/ampex/vplot/run ND boulder/ampex/vplot/symcomp.c ND boulder/ampex/vplot/tek ND boulder/ampex/vplot/tek.c ND boulder/ampex/vplot/vplotdb ND boulder/ampex/vplot/vplotdb.c ND boulder/caltech V6 boulder/caltech/address.c V6 boulder/caltech/bin V6  boulder/caltech/bin/args.v6 V6 boulder/caltech/bin/c.v6 V6 boulder/caltech/bin/com.v6 V6 boulder/caltech/bin/ed.v6 V6 boulder/caltech/bin/grep.v6 V6 boulder/caltech/bin/make.v6 V6 boulder/caltech/bin/pick.v6 V6 boulder/caltech/bin/qed.v6 V6 boulder/caltech/bin/qedbufs.v6 V6 boulder/caltech/bin/qedfile.v6 V6 boulder/caltech/blkio.c V6 boulder/caltech/com.c ND boulder/caltech/doc ND boulder/caltech/doc/args.1 ND boulder/caltech/doc/c.1 ND boulder/caltech/doc/com.1 ND boulder/caltech/doc/ed.1 ND boulder/caltech/doc/grep.1 ND boulder/caltech/doc/make.1 ND boulder/caltech/doc/pick.1 ND boulder/caltech/doc/prompt.1 ND boulder/caltech/doc/qed.1 ND boulder/caltech/doc/qedbufs.1 ND boulder/caltech/doc/qedfile.1 ND boulder/caltech/doc/shexecv.3 ND boulder/caltech/doc/tutorial V6 boulder/caltech/ed V6 boulder/caltech/ed/ed.c V6 boulder/caltech/ed/ed.ut V6 boulder/caltech/ed/grep.c V6 boulder/caltech/ed/ldiv.s V6 boulder/caltech/ed/prompt.c V6 boulder/caltech/ed/setjmp.h V6 boulder/caltech/ed/sgtty.h V6 boulder/caltech/ed/signal.h V6 boulder/caltech/getchar.c V6 boulder/caltech/getfile.c V6 boulder/caltech/glob.c V6 boulder/caltech/lib V6 boulder/caltech/main.c V6 boulder/caltech/makefile V6 boulder/caltech/misc.c V6 boulder/caltech/move.c V6 boulder/caltech/objectfiles V6 boulder/caltech/objectfiles/address.o V6 boulder/caltech/objectfiles/blkio.o V6 boulder/caltech/objectfiles/com.o V6 boulder/caltech/objectfiles/getchar.o V6 boulder/caltech/objectfiles/getfile.o V6 boulder/caltech/objectfiles/glob.o V6 boulder/caltech/objectfiles/main.o V6 boulder/caltech/objectfiles/misc.o V6 boulder/caltech/objectfiles/move.o V6 boulder/caltech/objectfiles/pattern.o V6 boulder/caltech/objectfiles/putchar.o V6 boulder/caltech/objectfiles/setaddr.o V6 boulder/caltech/objectfiles/string.o V6 boulder/caltech/objectfiles/subs.o V6 boulder/caltech/pattern.c V6 boulder/caltech/putchar.c V6 boulder/caltech/q V6 boulder/caltech/q/L.q V6 boulder/caltech/q/R.q V6 boulder/caltech/q/col.q V6 boulder/caltech/q/email.c V6 boulder/caltech/q/email.help V6 boulder/caltech/q/email.q V6 boulder/caltech/q/email.qed V6 boulder/caltech/q/grep.q V6 boulder/caltech/q/grepf.q V6 boulder/caltech/q/libzer V6 boulder/caltech/q/libzer.qed V6 boulder/caltech/q/man.q V6  boulder/caltech/q/manual V6 boulder/caltech/q/manual.qed V6 boulder/caltech/q/multiblanks.q V6 boulder/caltech/q/nextfile.q V6 boulder/caltech/q/pwd.q V6 boulder/caltech/q/qfile V6 boulder/caltech/q/qfile.q V6 boulder/caltech/q/run V6 boulder/caltech/q/split.q V6 boulder/caltech/q/un.q V6 boulder/caltech/q/writelen.q V6 boulder/caltech/read.me V6 boulder/caltech/setaddr.c V6 boulder/caltech/sgtty.h V6 boulder/caltech/string.c V6 boulder/caltech/subs.c V6 boulder/caltech/support V6 boulder/caltech/support/args.c V6 boulder/caltech/support/c.c V6 boulder/caltech/support/com.c V6 boulder/caltech/support/etcqedfile V6 boulder/caltech/support/make.c V6 boulder/caltech/support/pick.c V6 boulder/caltech/support/qedbufs.c V6 boulder/caltech/support/qedfile V6 boulder/caltech/support/qedfile.c V6 boulder/caltech/support/shexecv.c V6 boulder/caltech/vars.h ND* boulder/dpw ND* boulder/dpw/READ_ME ND* boulder/dpw/beastfile ND* boulder/dpw/beasts.c ND* boulder/dpw/beasts.h ND* boulder/dpw/bog.c ND* boulder/dpw/boginfo ND* boulder/dpw/bogwds ND* boulder/dpw/bsnoop.c ND* boulder/dpw/cursor.c ND* boulder/dpw/cursor.h ND* boulder/dpw/emp ND* boulder/dpw/emp/INFO ND* boulder/dpw/emp/INFO/INFO.MAC ND* boulder/dpw/emp/INFO/MAN.CCL ND* boulder/dpw/emp/INFO/MANFP.NR ND* boulder/dpw/emp/INFO/accept ND* boulder/dpw/emp/INFO/assault ND* boulder/dpw/emp/INFO/attack ND* boulder/dpw/emp/INFO/board ND* boulder/dpw/emp/INFO/build ND* boulder/dpw/emp/INFO/bye ND* boulder/dpw/emp/INFO/census ND* boulder/dpw/emp/INFO/change ND* boulder/dpw/emp/INFO/checkpoint ND* boulder/dpw/emp/INFO/collect ND* boulder/dpw/emp/INFO/commands ND* boulder/dpw/emp/INFO/contract ND* boulder/dpw/emp/INFO/country-roster ND* boulder/dpw/emp/INFO/declare ND* boulder/dpw/emp/INFO/defend ND* boulder/dpw/emp/INFO/deliver ND* boulder/dpw/emp/INFO/designate ND* boulder/dpw/emp/INFO/dissolve ND* boulder/dpw/emp/INFO/enlist ND* boulder/dpw/emp/INFO/execute ND* boulder/dpw/emp/INFO/fire ND* boulder/dpw/emp/INFO/fleetadd ND* boulder/dpw/emp/INFO/fly ND* boulder/dpw/emp/INFO/forecast ND* boulder/dpw/emp/INFO/grant ND* boulder/dpw/emp/INFO/headlines ND* boulder/dpw/emp/INFO/inav ND* boulder/dpw/emp/INFO/info ND* boulder/dpw/emp/INFO/innards ND* boulder/dpw/emp/INFO/ledger ND* boulder/dpw/emp/INFO/lend ND* boulder/dpw/emp/INFO/list ND* boulder/dpw/emp/INFO/load ND* boulder/dpw/emp/INFO/lookout ND* boulder/dpw/emp/INFO/map ND* boulder/dpw/emp/INFO/mine ND* boulder/dpw/emp/INFO/move ND* boulder/dpw/emp/INFO/nation ND* boulder/dpw/emp/INFO/navigate ND* boulder/dpw/emp/INFO/news ND* boulder/dpw/emp/INFO/offer ND* boulder/dpw/emp/INFO/overview ND* boulder/dpw/emp/INFO/plague ND* boulder/dpw/emp/INFO/power ND* boulder/dpw/emp/INFO/prayers ND* boulder/dpw/emp/INFO/radar ND* boulder/dpw/emp/INFO/read ND* boulder/dpw/emp/INFO/realm ND* boulder/dpw/emp/INFO/repay ND* boulder/dpw/emp/INFO/research ND* boulder/dpw/emp/INFO/route ND* boulder/dpw/emp/INFO/sector-types ND* boulder/dpw/emp/INFO/set ND* boulder/dpw/emp/INFO/shell ND* boulder/dpw/emp/INFO/ship ND* boulder/dpw/emp/INFO/ship-types ND* boulder/dpw/emp/INFO/spy ND* boulder/dpw/emp/INFO/syntax ND* boulder/dpw/emp/INFO/technology ND* boulder/dpw/emp/INFO/telegram ND* boulder/dpw/emp/INFO/tend ND* boulder/dpw/emp/INFO/time ND* boulder/dpw/emp/INFO/torpedo ND* boulder/dpw/emp/INFO/trade ND* boulder/dpw/emp/INFO/treaty ND* boulder/dpw/emp/INFO/unload ND* boulder/dpw/emp/INFO/update ND* boulder/dpw/emp/INFO/vote ND* boulder/dpw/emp/INFO/weather ND* boulder/dpw/emp/READ_ME ND* boulder/dpw/emp/UTIL ND* boulder/dpw/emp/UTIL/empchk.o ND* boulder/dpw/emp/UTIL/empcre.o ND* boulder/dpw/emp/UTIL/empfix.o ND* boulder/dpw/emp/emp1.o ND* boulder/dpw/emp/emp2.o ND* boulder/dpw/emp/emp3.o ND* boulder/dpw/emp/emp4.o ND* boulder/dpw/emp/emp5.o ND* boulder/dpw/emp/emp7.o ND* boulder/dpw/emp/empcom.a ND* boulder/dpw/emp/empdef.h ND* boulder/dpw/emp/empdis.o ND* boulder/dpw/emp/empglb.c ND* boulder/dpw/emp/empire.o ND* boulder/dpw/emp/empsub.a ND* boulder/dpw/emp/empsys.c ND* boulder/dpw/emp/replace ND* boulder/dpw/emp/run ND* boulder/dpw/gom_txt ND* boulder/dpw/gomoku.c ND* boulder/dpw/grams.c ND* boulder/dpw/gramsinfo ND* boulder/dpw/gramsrec ND* boulder/dpw/into.c ND* boulder/dpw/libP.a ND* boulder/dpw/mastermind.c ND* boulder/dpw/oracle.c ND* boulder/dpw/oxo.c ND* boulder/dpw/oxo.n ND* boulder/dpw/questfile ND* boulder/dpw/replace.c ND* boulder/dpw/st ND* boulder/dpw/st/Est_com.o ND* boulder/dpw/st/Est_main.o ND* boulder/dpw/st/NEst_com.o ND* boulder/dpw/st/NEst_main.o ND* boulder/dpw/st/READ_ME ND* boulder/dpw/st/helm.o ND* boulder/dpw/st/log.o ND* boulder/dpw/st/snoop.o ND* boulder/dpw/st/st_10q ND* boulder/dpw/st/st_def.h ND* boulder/dpw/st/st_glb.c ND* boulder/dpw/st/st_sub.o ND* boulder/dpw/st/st_txt.nr ND* boulder/dpw/st/st_viz.c ND* boulder/dpw/st/stlib.a ND* boulder/dpw/st/to.c ND* boulder/dpw/wand ND* boulder/dpw/wand/Fwander.o ND* boulder/dpw/wand/NFwander.o ND* boulder/dpw/wand/READ_ME ND* boulder/dpw/wand/a3.misc ND* boulder/dpw/wand/a3.wrld ND* boulder/dpw/wand/castle.misc ND* boulder/dpw/wand/castle.wrld ND* boulder/dpw/wand/library.misc ND* boulder/dpw/wand/library.wrld ND* boulder/dpw/wand/mac ND* boulder/dpw/wand/misc.nr ND* boulder/dpw/wand/tut.misc ND* boulder/dpw/wand/tut.wrld ND* boulder/dpw/wand/wandaid.nr ND* boulder/dpw/wand/wanddef.h ND* boulder/dpw/wand/wander.nr ND* boulder/dpw/wand/wander.o ND* boulder/dpw/wand/wandglb.c ND* boulder/dpw/wand/wrld.nr ND boulder/tools ND boulder/tools/tool01 ND boulder/tools/tool02 ND boulder/tools/tool03 ND boulder/tools/tool04 ND boulder/tools/tool05 ND boulder/tools/tool06 ND boulder/tools/tool07 ND boulder/tools/tool08 ND boulder/tools/tool09 ND boulder/tools/tool10 ND boulder/tools/tool11 ND boulder/tools/tool12 ND boulder/tools/tool13 ND boulder/tools/tool14 ND boulder/tools/tool15 ND boulder/tools/tool16 ND boulder/tools/tool17 ND delaware/campos/READ_ME ND delaware/campos/empty.doc V6 delaware/campos/ep.a.c V6 delaware/campos/ep.b.c ND delaware/campos/ep.doc ND delaware/campos/epa.defs ND delaware/campos/epahelp ND delaware/campos/epi.defs ND delaware/campos/epihelp ND delaware/cincinnati/grafix ND delaware/cincinnati/grafix/nec ND delaware/cincinnati/grafix/nec/run ND delaware/cincinnati/grafix/nec/arc.c ND delaware/cincinnati/grafix/nec/circle.c ND delaware/cincinnati/grafix/nec/close.c ND delaware/cincinnati/grafix/nec/dot.c ND delaware/cincinnati/grafix/nec/erase.c ND delaware/cincinnati/grafix/nec/label.c ND delaware/cincinnati/grafix/nec/line.c ND delaware/cincinnati/grafix/nec/linmod.c ND delaware/cincinnati/grafix/nec/move.c ND delaware/cincinnati/grafix/nec/open.c ND delaware/cincinnati/grafix/nec/point.c ND delaware/cincinnati/grafix/nec/space.c ND delaware/cincinnati/grafix/nec/subr.c ND delaware/cincinnati/grafix/nec/con.h ND delaware/cincinnati/grafix/nec/nec.a ND delaware/cincinnati/grafix/nec/core ND delaware/cincinnati/grafix/nec/nec ND delaware/cincinnati/grafix/nec/cont.a ND delaware/cincinnati/grafix/nec/a.out ND delaware/cincinnati/grafix/tek ND delaware/cincinnati/grafix/tek/arc.c ND delaware/cincinnati/grafix/tek/circle.c ND delaware/cincinnati/grafix/tek/close.c ND delaware/cincinnati/grafix/tek/cont.c ND delaware/cincinnati/grafix/tek/ctest.c ND delaware/cincinnati/grafix/tek/dot.c ND delaware/cincinnati/grafix/tek/erase.c ND delaware/cincinnati/grafix/tek/gchars.h ND delaware/cincinnati/grafix/tek/glabel.c ND delaware/cincinnati/grafix/tek/glabelp.c ND delaware/cincinnati/grafix/tek/label.c ND delaware/cincinnati/grafix/tek/line.c ND delaware/cincinnati/grafix/tek/linemod.c ND delaware/cincinnati/grafix/tek/move.c ND delaware/cincinnati/grafix/tek/open.c ND delaware/cincinnati/grafix/tek/point.c ND delaware/cincinnati/grafix/tek/scale.c ND delaware/cincinnati/grafix/tek/sine.c ND delaware/cincinnati/grafix/tek/space.c ND delaware/cincinnati/grafix/tek/subr.c ND delaware/cincinnati/grafix/tek/tek ND delaware/cincinnati/grafix/tek/tek.a ND delaware/cincinnati/grafix/tek/afplot.c ND delaware/cincinnati/grafix/tek/tekrun ND delaware/cincinnati/grafix/tek/test.c ND delaware/cincinnati/grafix/names ND delaware/cincinnati/grafix/driver.c ND delaware/cincinnati/grafix/plot.c.a ND delaware/cincinnati/grafix/READ_ME ND delaware/cincinnati/grafix/plot.a ND delaware/cincinnati/grafix/graph.c ND delaware/cincinnati/grafix/plot.6 ND delaware/cincinnati/grafix/plot.7 ND delaware/cincinnati/grafix/graph.6 ND delaware/cincinnati/nec ND delaware/cincinnati/nec/cont.a ND delaware/cincinnati/other ND delaware/cincinnati/other/cont.a ND delaware/cincinnati/ramtek ND delaware/cincinnati/ramtek/com ND delaware/cincinnati/ramtek/com/cont.a ND delaware/cincinnati/ramtek/lib ND delaware/cincinnati/ramtek/lib/cont.a ND delaware/cincinnati/READ_ME V6 delaware/cwru/pcc V6 delaware/cwru/pcc/list V6 delaware/cwru/pcc/src V6 delaware/cwru/pcc/src/pass1 V6 delaware/cwru/pcc/src/pass1/cgram.y V6 delaware/cwru/pcc/src/pass1/clocal.c V6 delaware/cwru/pcc/src/pass1/code.c V6 delaware/cwru/pcc/src/pass1/comm1.c V6 delaware/cwru/pcc/src/pass1/local.c V6 delaware/cwru/pcc/src/pass1/optim.c V6 delaware/cwru/pcc/src/pass1/pftn.c V6 delaware/cwru/pcc/src/pass1/scan.c V6 delaware/cwru/pcc/src/pass1/trees.c V6 delaware/cwru/pcc/src/pass1/xdefs.c V6 delaware/cwru/pcc/src/pass2 V6 delaware/cwru/pcc/src/pass2/address.c V6 delaware/cwru/pcc/src/pass2/allo.c V6 delaware/cwru/pcc/src/pass2/comm2.c V6 delaware/cwru/pcc/src/pass2/local2.c V6 delaware/cwru/pcc/src/pass2/match.c V6 delaware/cwru/pcc/src/pass2/order.c V6 delaware/cwru/pcc/src/pass2/reader.c V6 delaware/cwru/pcc/src/pass2/table.c V6 delaware/cwru/pcc/src/bugs V6 delaware/cwru/pcc/src/makefile V6  delaware/cwru/pcc/src/common V6 delaware/cwru/pcc/src/mac2defs V6 delaware/cwru/pcc/src/macdefs V6 delaware/cwru/pcc/src/manifest V6 delaware/cwru/pcc/src/mfile1 V6 delaware/cwru/pcc/src/mfile2 V6 delaware/cwru/pcc/src/ctype.h V6 delaware/cwru/pcc/src/cpp.dir V6 delaware/cwru/pcc/src/cpp.dir/cpp.c V6 delaware/cwru/pcc/src/cpp.dir/cpy.y V6 delaware/cwru/pcc/src/cpp.dir/makefile V6 delaware/cwru/pcc/src/cpp.dir/yylex.c V6 delaware/cwru/pcc/README V6 delaware/cwru/pcc/tour V6 delaware/cwru/pcc/tour/tour03.0 V6 delaware/cwru/pcc/tour/tour02.0 V6 delaware/cwru/pcc/tour/tour05.2 V6 delaware/cwru/pcc/tour/tour05.0 V6 delaware/cwru/pcc/tour/tour05.1 V6 delaware/cwru/pcc/tour/tour04.0 V6 delaware/cwru/pcc/tour/tour06.0 V6 delaware/cwru/pcc/tour/tour07.0 V6 delaware/cwru/pcc/tour/tour08.0 V6 delaware/cwru/pcc/tour/tour09.0 V6 delaware/cwru/pcc/tour/tour01.0 V6 delaware/cwru/pcc/tour/tour10.0 V6 delaware/cwru/pcc/tour/tour11.0 V6 delaware/cwru/pcc/tour/tour12.0 V6 delaware/cwru/pcc/tour/tour13.0 V6 delaware/cwru/pcc/tour/tour14.0 V6 delaware/cwru/pcc/tour/tour15.0 V6 delaware/cwru/pcc/tour/tour05.3 V6 delaware/cwru/pcc/tour/NOTES V6 delaware/cwru/pcc/tour/tour05.4 V6 delaware/cwru/pcc/tour/tour06.1 V6 delaware/cwru/pcc/tour/tour06.2 V6 delaware/cwru/pcc/tour/tour08.1 V6 delaware/cwru/pcc/tour/tour08.2 V6 delaware/cwru/pcc/tour/tour08.3 V6 delaware/cwru/pcc/tour/tour09.1 V6 delaware/cwru/pcc/tour/tour09.2 V6 delaware/cwru/pcc/tour/README V6 delaware/cwru/pcc/tour/tour.index V6 delaware/cwru/pcc/tour/page V6 delaware/cwru/pcc/tour/tmac.s V7 delaware/cwru.v7/sys V7 delaware/cwru.v7/sys/ov V7 delaware/cwru.v7/sys/ov/sys V7 delaware/cwru.v7/sys/ov/sys/acct.c V7 delaware/cwru.v7/sys/ov/sys/alloc.c V7 delaware/cwru.v7/sys/ov/sys/clock.c V7 delaware/cwru.v7/sys/ov/sys/fio.c V7 delaware/cwru.v7/sys/ov/sys/iget.c V7 delaware/cwru.v7/sys/ov/sys/machdep.c V7 delaware/cwru.v7/sys/ov/sys/malloc.c V7 delaware/cwru.v7/sys/ov/sys/nami.c V7 delaware/cwru.v7/sys/ov/sys/pipe.c V7 delaware/cwru.v7/sys/ov/sys/prf.c V7 delaware/cwru.v7/sys/ov/sys/prim.c V7 delaware/cwru.v7/sys/ov/sys/rdwri.c V7 delaware/cwru.v7/sys/ov/sys/sig.c V7 delaware/cwru.v7/sys/ov/sys/slp.c V7 delaware/cwru.v7/sys/ov/sys/subr.c V7 delaware/cwru.v7/sys/ov/sys/sys1.c V7 delaware/cwru.v7/sys/ov/sys/sys2.c V7 delaware/cwru.v7/sys/ov/sys/sys3.c V7 delaware/cwru.v7/sys/ov/sys/sys4.c V7 delaware/cwru.v7/sys/ov/sys/sysent.c V7  delaware/cwru.v7/sys/ov/sys/text.c V7 delaware/cwru.v7/sys/ov/sys/trap.c V7 delaware/cwru.v7/sys/ov/sys/ureg.c V7 delaware/cwru.v7/sys/ov/sys/mklib V7 delaware/cwru.v7/sys/ov/sys/fakemx.c V7 delaware/cwru.v7/sys/ov/sys/README V7 delaware/cwru.v7/sys/ov/sys/main.c V7 delaware/cwru.v7/sys/ov/dev V7 delaware/cwru.v7/sys/ov/dev/bio.c V7 delaware/cwru.v7/sys/ov/dev/cat.c V7 delaware/cwru.v7/sys/ov/dev/dh.c V7 delaware/cwru.v7/sys/ov/dev/dhdm.c V7 delaware/cwru.v7/sys/ov/dev/dhfdm.c V7 delaware/cwru.v7/sys/ov/dev/README V7 delaware/cwru.v7/sys/ov/dev/dkleave.c V7 delaware/cwru.v7/sys/ov/dev/dn.c V7 delaware/cwru.v7/sys/ov/dev/dsort.c V7 delaware/cwru.v7/sys/ov/dev/du.c V7 delaware/cwru.v7/sys/ov/dev/hp.c V7 delaware/cwru.v7/sys/ov/dev/ht.c V7 delaware/cwru.v7/sys/ov/dev/kl.c V7 delaware/cwru.v7/sys/ov/dev/mem.c V7 delaware/cwru.v7/sys/ov/dev/mx1.c V7 delaware/cwru.v7/sys/ov/dev/mx2.c V7 delaware/cwru.v7/sys/ov/dev/partab.c V7 delaware/cwru.v7/sys/ov/dev/pk0.c V7 delaware/cwru.v7/sys/ov/dev/pk1.c V7 delaware/cwru.v7/sys/ov/dev/pk2.c V7 delaware/cwru.v7/sys/ov/dev/pk3.c V7 delaware/cwru.v7/sys/ov/dev/rf.c V7 delaware/cwru.v7/sys/ov/dev/rk.c V7 delaware/cwru.v7/sys/ov/dev/rp.c V7 delaware/cwru.v7/sys/ov/dev/sys.c V7 delaware/cwru.v7/sys/ov/dev/tc.c V7 delaware/cwru.v7/sys/ov/dev/tm.c V7 delaware/cwru.v7/sys/ov/dev/tty.c V7 delaware/cwru.v7/sys/ov/dev/vp.c V7 delaware/cwru.v7/sys/ov/dev/vs.c V7 delaware/cwru.v7/sys/ov/dev/dc.c V7 delaware/cwru.v7/sys/ov/dev/dz.c V7 delaware/cwru.v7/sys/ov/dev/rl.c V7 delaware/cwru.v7/sys/ov/dev/rx2.c V7  delaware/cwru.v7/sys/ov/dev/dh.c.old V7 delaware/cwru.v7/sys/ov/dev/dhdm.c.old V7 delaware/cwru.v7/sys/ov/dev/dz.c.save V7 delaware/cwru.v7/sys/ov/dev/lh.c V7 delaware/cwru.v7/sys/ov/dev/ti.c V7 delaware/cwru.v7/sys/ov/dev/ds.c V7 delaware/cwru.v7/sys/ov/dev/mt.c V7 delaware/cwru.v7/sys/ov/dev/lx.c V7 delaware/cwru.v7/sys/ov/conf V7 delaware/cwru.v7/sys/ov/conf/mch.s V7 delaware/cwru.v7/sys/ov/conf/makefile V7 delaware/cwru.v7/sys/ov/conf/conf V7 delaware/cwru.v7/sys/ov/conf/mkconf.c V7 delaware/cwru.v7/sys/ov/conf/README V7 delaware/cwru.v7/sys/ov/conf/load V7 delaware/cwru.v7/sys/ov/conf/l.s V7 delaware/cwru.v7/sys/ov/conf/c.c V7 delaware/cwru.v7/sys/ov/conf/fix.c V7 delaware/cwru.v7/sys/ov/h V7 delaware/cwru.v7/sys/ov/h/acct.h V7 delaware/cwru.v7/sys/ov/h/buf.h V7  delaware/cwru.v7/sys/ov/h/callo.h V7 delaware/cwru.v7/sys/ov/h/timeb.h V7 delaware/cwru.v7/sys/ov/h/conf.h V7 delaware/cwru.v7/sys/ov/h/dir.h V7 delaware/cwru.v7/sys/ov/h/fblk.h V7 delaware/cwru.v7/sys/ov/h/file.h V7 delaware/cwru.v7/sys/ov/h/filsys.h V7 delaware/cwru.v7/sys/ov/h/ino.h V7 delaware/cwru.v7/sys/ov/h/inode.h V7 delaware/cwru.v7/sys/ov/h/map.h V7 delaware/cwru.v7/sys/ov/h/mount.h V7 delaware/cwru.v7/sys/ov/h/mpx.h V7 delaware/cwru.v7/sys/ov/h/stat.h V7 delaware/cwru.v7/sys/ov/h/tty.h V7 delaware/cwru.v7/sys/ov/h/pack.h V7 delaware/cwru.v7/sys/ov/h/types.h V7 delaware/cwru.v7/sys/ov/h/param.h V7 delaware/cwru.v7/sys/ov/h/prim.h V7 delaware/cwru.v7/sys/ov/h/proc.h V7 delaware/cwru.v7/sys/ov/h/pwd.h V7 delaware/cwru.v7/sys/ov/h/reg.h V7 delaware/cwru.v7/sys/ov/h/seg.h V7 delaware/cwru.v7/sys/ov/h/pk.p V7 delaware/cwru.v7/sys/ov/h/systm.h V7 delaware/cwru.v7/sys/ov/h/text.h V7 delaware/cwru.v7/sys/ov/h/pk.h V7 delaware/cwru.v7/sys/ov/h/mx.h V7 delaware/cwru.v7/sys/ov/h/user.h V7 delaware/cwru.v7/sys/ov/h/conf.h.old V7 delaware/cwru.v7/sys/ov/h/ti980.h V7 delaware/cwru.v7/sys/ov/README V7 delaware/cwru.v7/src V7 delaware/cwru.v7/src/cmd V7 delaware/cwru.v7/src/cmd/c V7 delaware/cwru.v7/src/cmd/c/README V7 delaware/cwru.v7/src/cmd/c/c0.h V7 delaware/cwru.v7/src/cmd/c/c11.c V7 delaware/cwru.v7/src/cmd/c/c02.c V7 delaware/cwru.v7/src/cmd/c/makefile V7 delaware/cwru.v7/src/cmd/standalone V7 delaware/cwru.v7/src/cmd/standalone/M.s V7 delaware/cwru.v7/src/cmd/standalone/README V7 delaware/cwru.v7/src/cmd/standalone/SYS.c V7  delaware/cwru.v7/src/cmd/standalone/srt0.s V7 delaware/cwru.v7/src/cmd/standalone/boot.c V7 delaware/cwru.v7/src/cmd/standalone/conf.c V7 delaware/cwru.v7/src/cmd/standalone/makefile V7 delaware/cwru.v7/src/cmd/standalone/prf.c V7 delaware/cwru.v7/src/cmd/standalone/rk.c V7 delaware/cwru.v7/src/cmd/standalone/rl.c V7 delaware/cwru.v7/src/cmd/standalone/rm.c V7 delaware/cwru.v7/src/cmd/standalone/saio.h V7 delaware/cwru.v7/src/cmd/standalone/ubmapset.c V7 delaware/cwru.v7/src/cmd/overlay V7 delaware/cwru.v7/src/cmd/overlay/README V7 delaware/cwru.v7/src/cmd/overlay/covld.c V7 delaware/cwru.v7/src/cmd/overlay/fix.c V7 delaware/cwru.v7/src/cmd/overlay/makefile V7 delaware/cwru.v7/src/cmd/overlay/ovpap.n V7 delaware/cwru.v7/src/cmd/overlay/x0.c V7 delaware/cwru.v7/src/cmd/overlay/x1.c V7 delaware/cwru.v7/src/cmd/overlay/x2.c V7 delaware/cwru.v7/src/cmd/overlay/xxx V7 delaware/cwru.v7/src/cmd/as V7 delaware/cwru.v7/src/cmd/as/README V7 delaware/cwru.v7/src/cmd/as/ov.s V7 delaware/cwru.v7/src/cmd/as/nov.s V7 delaware/cwru.v7/src/cmd/as/as11.s V7 delaware/cwru.v7/src/cmd/as/as27.s V7 delaware/cwru.v7/src/cmd/as/makefile V7 delaware/cwru.v7/src/cmd/cc.c V7 delaware/cwru.v7/src/cmd/beep.c V7  delaware/cwru.v7/src/cmd/code.c V7 delaware/cwru.v7/src/cmd/lpd.c V7 delaware/cwru.v7/src/cmd/lpdchar.c V7 delaware/cwru.v7/src/cmd/lpdkill.c V7 delaware/cwru.v7/src/cmd/lpr.c V7 delaware/cwru.v7/src/cmd/mc.c V7 delaware/cwru.v7/src/cmd/nm.c V7 delaware/cwru.v7/src/cmd/size.c V7 delaware/cwru.v7/src/cmd/sq.c V7 delaware/cwru.v7/src/cmd/ss.c V7 delaware/cwru.v7/src/cmd/strip.c V7 delaware/cwru.v7/src/cmd/syms.c ND delaware/geotronics/rat ND delaware/geotronics/rat/ReadMe.doc ND delaware/geotronics/rat/r1.c.e ND delaware/geotronics/rat/lex.c.e ND delaware/geotronics/rat/SysDef.r ND delaware/geotronics/rat/r.g.e ND delaware/geotronics/rat/r2.c.e ND delaware/geotronics/rat/mkratfor ND delaware/geotronics/s1 ND delaware/geotronics/s1/cdb1.c.e ND delaware/geotronics/s1/db1.s.e ND delaware/geotronics/s1/getty.c.e ND delaware/geotronics/s1/ReadMe.doc ND delaware/geotronics/s1/ac.c.e ND delaware/geotronics/s1/icheck.c.e ND delaware/geotronics/s1/login.c.e ND delaware/geotronics/s1/cc.c.e ND delaware/geotronics/s2 ND delaware/geotronics/s2/rc.c.e ND delaware/geotronics/s2/stty.c.e ND delaware/geotronics/s2/su.c.e ND delaware/geotronics/s2/ReadMe.doc ND delaware/geotronics/s2/ps.c.e ND delaware/geotronics/s3 ND delaware/geotronics/s3/ttyn.s.e ND delaware/geotronics/s3/ReadMe.doc ND delaware/geotronics/s5 ND delaware/geotronics/s5/pipe.s.e ND delaware/geotronics/s5/ReadMe.doc ND delaware/geotronics/s5/reset.s.e ND delaware/geotronics/s7 ND delaware/geotronics/s7/ReadMe.doc ND delaware/geotronics/s7/nroff1.s.e ND delaware/geotronics/s6 ND delaware/geotronics/s6/order.c ND delaware/geotronics/s6/pg.c ND delaware/geotronics/s6/qume.c ND delaware/geotronics/s6/retab.c ND delaware/geotronics/s6/ReadMe.doc ND delaware/geotronics/s6/rtblap.c ND delaware/geotronics/sys ND delaware/geotronics/sys/dmr ND delaware/geotronics/sys/dmr/lp.c.e ND delaware/geotronics/sys/dmr/mem.c.e ND delaware/geotronics/sys/dmr/rk.c.e ND delaware/geotronics/sys/dmr/rp.c.e ND delaware/geotronics/sys/dmr/tm.c.e ND delaware/geotronics/sys/dmr/tty.c.e ND delaware/geotronics/sys/dmr/bio.c.e ND delaware/geotronics/sys/dmr/dz.c ND delaware/geotronics/sys/ken ND delaware/geotronics/sys/ken/prf.c.e ND delaware/geotronics/sys/ken/sys2.c.e ND delaware/geotronics/sys/ken/sysent.c.e ND delaware/geotronics/sys/ken/trap.c.e ND delaware/geotronics/sys/ken/main.c.e ND delaware/geotronics/sys/conf ND delaware/geotronics/sys/conf/mkconf.c.e ND delaware/geotronics/sys/conf/m40.s.e ND delaware/geotronics/sys/ReadMe.doc ND delaware/geotronics/sys/param.h.e ND delaware/geotronics/sys/tty.h.e ND delaware/geotronics/sys/mkunix ND delaware/geotronics/fort ND delaware/geotronics/fort/fx ND delaware/geotronics/fort/fx/fhd.s.e ND delaware/geotronics/fort/io ND delaware/geotronics/fort/io/io6.s.e ND delaware/geotronics/fort/io/io1.s.e ND delaware/geotronics/fort/io/mkio ND delaware/geotronics/fort/rt ND delaware/geotronics/fort/rt/r2.s.e ND delaware/geotronics/fort/rt/r3.s.e ND delaware/geotronics/fort/rt/r4.s.e ND delaware/geotronics/fort/rt/r7.s.e ND delaware/geotronics/fort/rt/r8.s.e ND delaware/geotronics/fort/rt/mkrt ND delaware/geotronics/fort/ReadMe.doc ND delaware/geotronics/fort/mkfortran ND delaware/geotronics/fort/f4 ND delaware/geotronics/fort/f4/f47.s.e ND delaware/geotronics/hlp ND delaware/geotronics/hlp/ratfor.doc ND delaware/geotronics/hlp/commands.hlp ND delaware/geotronics/hlp/ReadMe.doc ND delaware/geotronics/hlp/dir.hlp ND delaware/geotronics/hlp/rtblap.hlp ND delaware/geotronics/hlp/fortran.hlp ND delaware/geotronics/hlp/games.hlp ND delaware/geotronics/hlp/help.hlp ND delaware/geotronics/hlp/logout.hlp ND delaware/geotronics/hlp/man.hlp ND delaware/geotronics/hlp/order.hlp ND delaware/geotronics/hlp/pg.hlp ND delaware/geotronics/hlp/print.hlp ND delaware/geotronics/hlp/ratfor.hlp ND delaware/geotronics/hlp/retab.hlp ND delaware/geotronics/hlp/terminal.hlp ND delaware/geotronics/etc ND delaware/geotronics/etc/acct ND delaware/geotronics/etc/backup ND delaware/geotronics/etc/SysMgr ND delaware/geotronics/etc/ReadMe.doc ND delaware/geotronics/etc/deact ND delaware/geotronics/etc/sucrontab ND delaware/geotronics/etc/qclean ND delaware/geotronics/etc/rc ND delaware/geotronics/etc/react ND delaware/geotronics/etc/scan ND delaware/geotronics/etc/scram ND delaware/geotronics/etc/shcomp ND delaware/geotronics/etc/shutdown ND delaware/geotronics/etc/startup ND delaware/geotronics/etc/ttys.dz ND delaware/geotronics/etc/ttys.nodz ND delaware/geotronics/Contents ND delaware/geotronics/bin ND delaware/geotronics/bin/ReadMe.doc ND delaware/geotronics/bin/adm3a ND delaware/geotronics/bin/clr ND delaware/geotronics/bin/dir ND delaware/geotronics/bin/help ND delaware/geotronics/bin/man ND delaware/geotronics/bin/print ND  delaware/geotronics/bin/transfor ND delaware/geotronics/bin/vt100 ND delaware/geotronics/bin/formfeed ND delaware/pittsburgh/wetzel ND delaware/pittsburgh/wetzel/compat ND delaware/pittsburgh/wetzel/compat/unixemts.c ND delaware/pittsburgh/wetzel/compat/compat.s ND delaware/pittsburgh/wetzel/compat/defs.h ND delaware/pittsburgh/wetzel/compat/memsiz.s ND delaware/pittsburgh/wetzel/compat/unix7sys.h ND delaware/pittsburgh/wetzel/compat/runcompat.c ND delaware/pittsburgh/wetzel/compat/unix6sys.h ND delaware/pittsburgh/wetzel/compat/Readme ND delaware/pittsburgh/wetzel/compat/unixtraps.c ND delaware/pittsburgh/wetzel/compat/dofloat.c ND delaware/pittsburgh/wetzel/compat/Makefile ND delaware/pittsburgh/wetzel/compat/rt11.h ND delaware/pittsburgh/wetzel/compat/dosig.c ND delaware/pittsburgh/wetzel/compat/unixhdr.h ND delaware/pittsburgh/wetzel/compat/v6run.1 ND delaware/pittsburgh/wetzel/compat/modshell ND delaware/pittsburgh/wetzel/compat/modshell/Makefile ND delaware/pittsburgh/wetzel/compat/modshell/compat.c ND delaware/pittsburgh/wetzel/compat/modshell/name.c.ediff ND delaware/pittsburgh/wetzel/compat/modshell/defs.h.ediff ND delaware/pittsburgh/wetzel/compat/modshell/v6flag.c ND delaware/pittsburgh/wetzel/compat/modshell/service.c.edif ND delaware/pittsburgh/wetzel/compat/modshell/msg.c.ediff ND delaware/pittsburgh/wetzel/compat/unixstart.c ND delaware/pittsburgh/wetzel/compat/unix6sysn.h ND delaware/pittsburgh/wetzel/compat/unix7sysn.h ND delaware/pittsburgh/rosenberg ND delaware/pittsburgh/rosenberg/LS ND delaware/pittsburgh/rosenberg/dot ND delaware/pittsburgh/rosenberg/dot/CD ND delaware/pittsburgh/rosenberg/dot/ed ND delaware/pittsburgh/rosenberg/dot/include ND delaware/pittsburgh/rosenberg/dot/td ND delaware/pittsburgh/rosenberg/dot/CC ND delaware/pittsburgh/rosenberg/dot/pd ND delaware/pittsburgh/rosenberg/DOC ND delaware/pittsburgh/rosenberg/MAKSRC ND delaware/pittsburgh/rosenberg/CLEANUP ND delaware/pittsburgh/rosenberg/scripts ND delaware/pittsburgh/rosenberg/scripts/main.c.ed ND delaware/pittsburgh/rosenberg/scripts/msg.c.ed ND delaware/pittsburgh/rosenberg/scripts/name.c.ed ND delaware/pittsburgh/rosenberg/scripts/service.c.ed ND delaware/pittsburgh/rosenberg/scripts/xec.c.ed ND delaware/pittsburgh/rosenberg/scripts/macro.c.ed ND delaware/pittsburgh/rosenberg/scripts/extend.c ND delaware/pittsburgh/rosenberg/scripts/error.c.ed ND delaware/pittsburgh/rosenberg/scripts/extend.h ND delaware/pittsburgh/rosenberg/scripts/ctype.c.ed ND delaware/pittsburgh/rosenberg/scripts/sym.h.ed ND delaware/pittsburgh/rosenberg/scripts/ctype.h.ed ND  delaware/pittsburgh/rosenberg/scripts/defs.h.ed ND delaware/pittsburgh/rosenberg/scripts/ERRNO.ED ND delaware/pittsburgh/rosenberg/scripts/xec.fix ND delaware/pittsburgh/rosenberg/scripts/Makefile ND delaware/pittsburgh/rosenberg/scripts/LOGIN.ED ND delaware/pittsburgh/rosenberg/RESTORE ND delaware/pittsburgh/rosenberg/SAVE ND delaware/pittsburgh/rosenberg/extend.c ND delaware/pittsburgh/rosenberg/extend.h ND delaware/pittsburgh/rosenberg/README ND delaware/tektronix/contents ND delaware/tektronix/make.dirs ND delaware/tektronix/maketape ND delaware/tektronix/de_arch ND delaware/tektronix/de_rm_arch ND delaware/tektronix/rm_arch ND delaware/tektronix/I_AM_READ_1st ND delaware/tektronix/READ_ME ND delaware/tektronix/READ_ME_TOO ND delaware/tektronix/bb.post ND delaware/tektronix/bb.post/READ_ME ND delaware/tektronix/bb.post/cont.a V7 delaware/tektronix/include V7 delaware/tektronix/include/sys V7 delaware/tektronix/include/sys/cont.a V7 delaware/tektronix/include/cont.a V7 delaware/tektronix/include/READ_ME ND delaware/tektronix/pas ND delaware/tektronix/pas/FROMTAPE ND delaware/tektronix/pas/NOTE.FOR.11-34 ND delaware/tektronix/pas/READ_ME ND delaware/tektronix/pas/READ_ME.nr ND delaware/tektronix/pas/TREE.org ND delaware/tektronix/pas/bin ND delaware/tektronix/pas/bin/cont.a ND delaware/tektronix/pas/doc ND delaware/tektronix/pas/doc/ref_manual ND delaware/tektronix/pas/doc/ref_manual/READ.ME ND delaware/tektronix/pas/doc/ref_manual/cont.a ND delaware/tektronix/pas/doc/cont.a ND delaware/tektronix/pas/etc ND delaware/tektronix/pas/etc/cont.a ND delaware/tektronix/pas/lib ND delaware/tektronix/pas/lib/cont.a ND delaware/tektronix/pas/man ND delaware/tektronix/pas/man/V7 ND delaware/tektronix/pas/man/V7/cont.a ND delaware/tektronix/pas/man/V6 ND delaware/tektronix/pas/man/V6/cont.a ND delaware/tektronix/pas/man/READ_ME ND delaware/tektronix/pas/new ND delaware/tektronix/pas/new/newlib V6 delaware/tektronix/pas/new/newlib/cont.a ND delaware/tektronix/pas/new/newas ND delaware/tektronix/pas/new/newas/READ_ME ND delaware/tektronix/pas/new/newas/NEW_READ_ME V6 delaware/tektronix/pas/new/newas/cont.a ND delaware/tektronix/pas/new/newcc ND delaware/tektronix/pas/new/newcc/READ_ME V6 delaware/tektronix/pas/new/newcc/cont.a ND delaware/tektronix/pas/new/newld ND delaware/tektronix/pas/new/newld/READ_ME ND delaware/tektronix/pas/new/newld/NEW_READ_ME ND delaware/tektronix/pas/new/newld/install V6 delaware/tektronix/pas/new/newld/org.ld.c ND delaware/tektronix/pas/new/newld/run V7 delaware/tektronix/pas/new/newld/v7.ld.c V6  delaware/tektronix/pas/new/newld/vu.ld.c ND delaware/tektronix/pas/new/v7lib V7 delaware/tektronix/pas/new/v7lib/cont.a ND delaware/tektronix/pas/ovl ND delaware/tektronix/pas/ovl/em1:int ND delaware/tektronix/pas/ovl/em1:int/cont.a ND delaware/tektronix/pas/ovl/cont.a ND delaware/tektronix/pas/src ND delaware/tektronix/pas/src/ass ND delaware/tektronix/pas/src/ass/READ_ME ND delaware/tektronix/pas/src/ass/cont.a ND delaware/tektronix/pas/src/int ND delaware/tektronix/pas/src/int/READ_ME ND delaware/tektronix/pas/src/int/cont.a ND delaware/tektronix/pas/src/misc ND delaware/tektronix/pas/src/misc/cont.a ND delaware/tektronix/pas/src/misc/READ_ME ND delaware/tektronix/pas/src/pem ND delaware/tektronix/pas/src/pem/READ_ME ND delaware/tektronix/pas/src/pem/cont.a ND delaware/tektronix/pas/src/test ND  delaware/tektronix/pas/src/test/cont.a ND delaware/tektronix/pas/src/libem ND delaware/tektronix/pas/src/libem/READ_ME ND delaware/tektronix/pas/src/libem/cont.a ND delaware/tektronix/pas/src/libpr ND delaware/tektronix/pas/src/libpr/READ_ME ND delaware/tektronix/pas/src/libpr/cont.a ND delaware/tektronix/pas/src/lib2 ND delaware/tektronix/pas/src/lib2/READ_ME ND delaware/tektronix/pas/src/lib2/cont.a ND delaware/tektronix/pas/src/libP ND delaware/tektronix/pas/src/libP/READ_ME ND delaware/tektronix/pas/src/libP/cont.a ND delaware/tektronix/pas/src/opt ND delaware/tektronix/pas/src/opt/cont.a ND delaware/tektronix/pas/src/pdp ND delaware/tektronix/pas/src/pdp/READ_ME ND delaware/tektronix/pas/src/pdp/cont.a ND delaware/tektronix/pas/src/rundir ND delaware/tektronix/pas/src/rundir/cont.a ND  delaware/tektronix/pas/src/odds ND delaware/tektronix/pas/src/odds/cont.a ND delaware/tektronix/pas/src/cont.a ND delaware/tektronix/pas/NEW_READ_ME ND delaware/tektronix/pas/V7.DISCLAIMER ND delaware/tektronix/pas/suite ND delaware/tektronix/pas/suite/cont.a ND delaware/tektronix/sh ND delaware/tektronix/sh/READ_ME ND delaware/tektronix/sh/cont.a ND delaware/tektronix/tty ND delaware/tektronix/tty/READ_ME V7 delaware/tektronix/tty/cont.a tektronix/pas/src/odds ND delaware/tektronix/pas/src/odds/cont.a ND delaware/tektronix/pas/src/cont.a ND delaware/tektronix/pas/NEW_READ_ME ND delaware/tektronix/pas/V7.DISCLAIMER ND delaware/tektronix/pas/suite ND delaware/tektronix/pas/suite/cont.a ND delaware/tektronix/sh ND delaware/tektronix/sh/READ_ME ND delaware/tektronix/sh/cont.a ND delaware/tektronix/tty ND delaware/tektronix/tty/READ_ME V7 delaware/tektronix/This tape contains all files since your signed form indicates that you have a Version 7 source license. ware/tektronix/pas/src/cont.a ND delaware/tektronix/pas/NEW_READ_ME ND delaware/tektronix/pas/V7.DISCLAIMER ND delaware/tektronix/pas/suite ND delaware/tektronix/pas/suite/cont.a ND delaware/tektronix/sh ND delaware/tektronix/sh/READ_ME ND delaware/tektronix/sh/cont.a ND delaware/tektronix/tty ND delaware/tektronix/tty/READ_ME V7 delaware/tektronix/1 & 6 % *w %#`t! 4e *@ @m@- E7fM E7\M_@d ̂ xK%@7MgvKc d % t! 4% *TL z TL  "TL  !E%@K!L% J# J  J   7pL  7`L  J J J JA1`@ȋ_ J t! 4  *@ȥbfJ^JZJ r7RJ7JJLJ 6 x6 6# B 7>JI6#;t! 4%  +G6# z 7 7 R b 7 IeX# > %I~t! 4% *w   e# >  e# > %t p * ) W- A@D6$RI `%6$ > % (I  I_$6#C_ 7 I+ * W- A@D68& H68H %  HH lfd^6# , e nH fH ^H6#  NH6#   _f6# ^ 6# TL beTL  _f6# ^ 6# z G3 ~I0-lpI,k-hI bI$TL TL6# | TL6#]t! 4eztrl_TL 7G 6# B 7lG6#vt! 4%VG &E 8 5u/ . W- A@D6$F `% F6$F % F F  F_4F VPJDTL Ne F_4TL _4w lTM P  wd̥./e6# z "6#  6#t! 4%E%@ 7GE7Gq6# b 7oE7dE7PLH^Z875`v &!&E 8 7fwd Tw ^# %q( t! 4  *6# 6#   wE%@ 7FE7Fw D DjF& 47 D7LF 4%BF 8F& X%(F * ba0&    `D \D wVw @D E< 2D 2D&  &  "&   w &  zEEWt@P&  %  JE& z& %  C-fP-^H t! 4%"&  %@C--  t! 4  *&  3 C$ ʕ/ʕ/ ʋʥ/ "&  5%E%@ʕ/&  6  >DEzWt@P&  b&  _Hw lDC _2 HLB6$& `%-_8wfFwbFw ^Fw ZFT& < wfA@9w w DB  E  Ґ%  B- w@w  E    7E E0E ^EB $ҐE E EEE % B %:% w%:%0%9Wp D`eD- w D  & & %4  0w w Dd!-< w e̥wf !̥af B f  &  % f B  ̥rw  Nfef %w w C  E d! %  C- w @w l!fef %w w D   l!    ~ zl!  wD w 4 D .@w  4 eT4 && `%4 % 4 E w wBDBB %wB f& & e wD 7 B7 B BׯB- zB xBׯrB00pBw^B7 `B .|wTB!Bw: J X b& %~ *ww wr wn !7d;ww N ww Ae vB, 7 =55 a  a!KE - %!! %} * =%=eE7|=  % w  e  ? J= `e 7v !p  a7b  Z V:?T P ew D74 E wfw4 w0 !wV fw w "w6 w :N  w4w $  @ 7|archive %s %s cpio -i[dmrtuv] [pattern] /*/dev/ttyr/dev/ttywOptions must include o|i|p <%s> ? %s TRAILER!!!TRAILER!!!Cannot link <%s> & <%s> <%s> ? %l blocks <%s> ? Out of phase--get help (or try `_cpio' for old format) TRAILER!!!Rename <%s> Skipped ...Cannot mknod <%s> current <%s> newer Attempt to pass file to self! Cannot create <%s> Read error Cannot write. %s linked to %s Cannot link <%s>&<%s>. Out of core for links %-7o%-6s%-6s%-6d%7D %s %s */bin/mkdirmkdirmkdir <%s> failed /etc/passwdrReading bad file doxfftebg:cHsrlrLurDOXU(null)writing OO!!!!!!corrupt arena PF0"4"M:/ESTEDTDay Mon 00 00:00:00 1900 SunMonTueWedThuFriSatJanFebMarAprMayJunJulAugSepOctNovDec  Tmkdirmkdir <%s> failed /etc/passwdrReading bad file doxfftebg:cHsrlrLurDOXU(null)writing OO!!!!!!corr"1 0  6 >  67rV % jw r"%#v#K##$& e j@ @m@- 7R 7Q_@b Ђ x"6P%#@7QjPf H % #$& % jQ  #Q  'Q n &E%@Oj&FQ%# O& O# O  O##  7 Q##  7P  fO ZO VO VOA1`@ȋ_ *O #$&   jN ȥb O ONNN r7N7NN 6 x# '  7NI'#$& %  +$'  7 ~%7 |%$ 0 7j%nNeX' , %tN=$$& % jw 6% 2%(%e' , %e' , %$$* ) W- A@D(M  %( , % M  M_R'$_H 7Mr$n$+ * W- A@D<& NM<BM !%  (M"M ####' e L L L'  L' N  _' b ' Q 0eQ  _' b '  tL1 N.-#M*-#M M#Q Q' r Q'$$& e##""lQ 7L '  7K'5$$& %K x"t"/ . W- A@D(K  % K(K !% K hK  bK_bXK !!!!Q e .K_bQ N_bw R   w̥./e'  '' n 'H$$& %P!E%@ 78L6!E7.Lq`!' 0 7f!!T!!P!!B!!>! E74!!8!!4! (!5`   7!w! !w ' %q P$$&   j' $'   w E%@ 7JK E7@Kw LD I K& 47 I7$K %J ^J& F%J j 0a0$&  $ " I I ww D JM H H$&  $&  '& n  wn & l 0Jrl&  `TE& % $$& %%2  I'& n  (H -  -$%G-- $$&   j&  3 G$ ʕ/ʕ/ ʋʥ/ '& n 5%LE%@ʕ/&  $ H@:& %,& l _Lw DC _ LG(&  %-G  %$&   jFL(L FLeL L ww DC ( FFf  &  e   f   4  Հ rw D&      &  wz w j &-b wd ef >@w 6 N  Pw0 w Ne < f > ef&@ 5uNe w/%J %K  t% t5% z N z 5   %D-D-% eu Ne  wD w 4 DC%: e`m e rfw w Q@f& : e5uQ@f& <e5u eeQu  VY< ff eR< ff eC r<R r< A@epe@ f& ~ew? F  5 $u   5u F   5`u`u \?D7X? %n   &  0!&|  7 ?VYwnw ^archive %s %s cpio -i[cdmrtuv] [pattern] /*/dev/ttyr/dev/ttywOptions must include o|i|p <%s> ? %s TRAILER!!!TRAILER!!!Cannot link <%s> & <%s> <%s> ? %l blocks <%s> ? Out of phase--get help (or try `_cpio' for old format) TRAILER!!!Rename <%s> Skipped ...Cannot mknod <%s> current <%s> newer Attempt to pass file to self! Cannot create <%s> Read error Cannot write. %s linked to %s Cannot link <%s>&<%s>. Out of core for links %-7o%-6s%-6s%-6d%7D %s %s */bin/mkdirmkdirmkdir <%s> failed @(#)sname 1.1/etc/passwdr^dDoPxf,egcslLfuDrjDHOTX|U(null)TT&M:/Day Mon 00 00:00:00 1900 SunMonTueWedThuFriSatJanFebMarAprMayJunJulAugSepOctNovDec!;6 vY# mkdir <%s> failed @(#)sname 1.1/etc/passwdr^dDoPxf,egcslL CPIO(I) UNIX Programmer's Manual CPIO(I) NAME cpio - copy file archives in and out bcpio - copy file archives in and out in blocks of 5120 bytes SYNOPSIS [_b]_c_p_i_o -o[v] [_b]_c_p_i_o -i[drtuv] [ pattern ] _c_p_i_o -p[dlruv] [ pattern ] directory DESCRIPTION [_B]_c_p_i_o -_o (copy out) reads the standard input for a list of pathnames and copies those files onto the standard output together with pathname and status information. [_B]_c_p_i_o -_i (copy in) extracts from the standard input, which is the product of a previous ``[_b]_c_p_i_o -_o'', files whose names are selected by a _p_a_t_t_e_r_n given in the name-generating syntax of _s_h(I). The _p_a_t_t_e_r_n meta-characters `?', `*', `[...]' will match `/' characters. The _p_a_t_t_e_r_n argument defaults to "*". _C_p_i_o -_p (pass) copies out and in in a single operation. Destination pathnames are interpreted relative to the named _d_i_r_e_c_t_o_r_y. The options are: _d _D_i_r_e_c_t_o_r_i_e_s are to be created as needed. _r Interactively _r_e_n_a_m_e files. If the user types a null line, the file is skipped. _t Print a _t_a_b_l_e _o_f _c_o_n_t_e_n_t_s of the input. No files are created. _u Copy _u_n_c_o_n_d_i_t_i_o_n_a_l_l_y (normally, an older file will not replace a newer file with the same name). _v _V_e_r_b_o_s_e: causes a list of file names to be printed. When used with the _t option, the table of contents looks like an ``ls -l'' (see _l_s(I)). _l Whenever possible, link files rather than copying them. Usable only with the -_p option. _m Retain previous file modified time (only for the super-user). Printed 10/13/80 5/31/80 1 CPIO(I) UNIX Programmer's Manual CPIO(I) The first example below copies the contents of a directory into an archive; the second duplicates a directory hierar- chy: ls | [b]cpio -o >/dev/[r]mt0 chdir olddir find . -print | cpio -pdl newdir SEE ALSO ar(I), cpio(V) BUGS Path names are restricted to 128 characters. If there are too many unique linked files, the program runs out of memory to keep track of them and subsequent linking information is lost. The mechanism for deciding on blocked or unblocked is to see if the name by which it is called starts with a "b". One must still specify a "raw" tape device to avoid cryptic error messages. Printed 10/13/80 5/31/80 2 ath names are restricted to 128 characters. If there are too manqf/A\4/adiqe/*wz4/adi/READ_METhese programs were announced during my session at the USENIX conference in Boulder, Colorado, Jan 79. The MENU program accepts a data file which is presented to the user as a set of 'choices'. The user may be locked into a menu or hierarchy of menus, thus forcing a fixed set of choices. Particular applications include setting up a 'shell' for untrained system-users who do not need the power of '/bin/sh'. The TCOM program provides the UNIX user with a window through the UNIX system to the outside world. I use it to log onto other computers and keep a local record of my terminal sessions. In addition, it may be used to transfer ASCII data files between systems when no other means is available. qd/*xz z4/adi/menu.1.th MENU I 12/79 .sh NAME menu - offer a set of options at the terminal .sh SYNOPSIS MENU menufile [debug] .sh DESCRIPTION Menu prints a tableau on the terminal and then requests a choice from the user. Invalid choices are rejected. Valid choices result in a CHDIR to another directory (if specified) and execution of the program specified in the menufile for the respective choice with the arguments following the program name forwarded to the program at execution. .sh EXAMPLE .nf *** AU #1 in the P3 Lab at NADC *** Choose Option (by number): : Unit Information.::/bin/cat:unitf Chassis History.::/bin/cat:c_hist Module Referral.:data/au1:/usx/navy/run/ref:Referral Program MAR data.::/usx/navy/run/menu:m.MAR Post Office.::/usx/navy/run/menu:m.mail Quit. .fi .sp 2 The data up to the line which begins with ':' (colon) is printed out as a header in the same format as entered. The succeeding lines are printed as the choices. .br Entries with no program to run will cause the menu to exit which usually results in a return to the caller. .sp An INTERRUPT from the terminal during printing of the selections will cause an immediate jump to "choice?". .sp Response of "?" from the user will reprint the menu. This is the way to reprint the selections if you stopped them in the middle with an INTERRUPT. .sp A response of "q" or a "return" (empty line) will exit. .sh DIAGNOSTICS Complains if the choice is invalid. Also complains if the menu file is missing or not recognizable in format. If the called program fails to execute, a fork/execute error will result. .sp A debugging aid may be turned on by giving two calling arguments. .sh BUGS The maximum number of choices is set at compile-time. Also, the entire menu file must fit into a buffer in the program. Check the buffer size if you are using more than "one screen" of menu. .sh AUTHOR Neil P. Groundwater, Analytic Disciplines Inc, Vienna, VA. qc/*xz <4/adi/menu.c# /* * Generalized Menu Program. * * Contributed to USENIX, February, 1980. * Please refer questions and any bugs to: * Neil Groundwater * c/o Analytic Disciplines, Inc. * 8320 Old Courthouse Road #300 * Vienna, Virginia 22180 * (703) 893-6140 * * Compiled by: cc -O menu.c -lp May use "-n" to share text if heavily used. * * Expects to be called with a filename as argument. * File form: * Header question. * : (delimiter) * Choice::Prog_to_execute:Arg_to_prog * Choice::Prog_to_execute:Arg[1]_to_prog:Arg[2]_to_prog... * Choice:Directory:Prog_to_execute * Choice (simply exits) * * Menu will be presented listing choices and selection #'s. * Valid selection number will execute desired program. * Optional 2nd arg is directory to change to before exec. * * nl will exit, * 'q' will exit. */ /* * This buffer must be at least as large as the file * containing the menu selections. */ char bufr[2048]; /* used for user response */ char buf_in[80]; /* flag for first pass to allow reset/setexit to setup */ int first {0}; #define NSEL 24 /* max # of selections */ #define N_ARG 4 /* Allows 4 prog args */ struct sel { char *a[4+N_ARG]; /* Choice, directory, progname, a[1], */ /* a[2], a[3], .., null. */ } sel[NSEL]; struct sel *selp; /* Version 2.1 */ main(argc, argv) char *argv[]; { int num; int fd; int nchs, ii; register char *bufp; int siz; int status; /* child status */ extern int onintr(), reset(); signal(2, 1); /* shut off until ready to catch */ signal(3, 1); /* this one stays off */ if ((argc < 2) || ((fd = copen(argv[1], 'r')) < 0)) { printf("Can't find Menu Data file: %s\n", argv[1]); cexit(); } /* load whole header into bufr */ bufp = bufr; while (((siz = getstr(fd, bufp)) > 0) && (*bufp != ':')) { bufp =+ siz; /* move pointer */ *(bufp-1) = '\n'; /* put back the nl */ } *bufp++ = '\0'; /* null terminate header */ selp = sel; /* load the choice lines and set up pointers */ for (nchs=0; nchsa[0] = bufp; /* start of rec */ bufp =+ siz; /* move ptr to end of line */ *(bufp-1) = '\0'; /* null the nl */ /* Null colons and add zero-last-ptr */ for (ii=0; selp->a[ii+1]=colon(selp->a[ii]); ii++); selp++; } cclose(fd);  /* read selection from user... after selection completes repeat menu, ad infinitum */ for (;;) { /* find a good number */ setexit(); /* returns here on intr */ signal(2, onintr); if (first++) { for (;;) { /* get a response */ printf("\nSelection? "); if (getstr(0, buf_in) == 0) cexit(); if ((buf_in[0] == 'q') || (buf_in[0] == '\0')) cexit(); if (buf_in[0] == '?') goto reprint; num = atoi(buf_in) - 1; if ((num >= 0) && (num < nchs)) break; printf("* Invalid Choice - Try Again *\n"); } selp = &sel[num]; if (argc > 2) { /* Print Trace */ printf("Choice= %s\n", selp->a[0]); if (selp->a[1] != 0) printf("Dir= %s\n", selp->a[1]); if (selp->a[2] != 0) printf("Prog= %s\n", selp->a[2]); for (ii=3; selp->a[ii] != 0; ii++) printf("Arg[%d]= %s\t", ii-2, selp->a[ii]); printf("\n"); } if (selp->a[2] == 0) /* exit - no prog to run */ cexit(); signal(2, 1); /* don't interrupt here */ if (fork() == 0) { /* child */ signal(2, 0); if ((selp->a[1] != 0) && (chdir(selp->a[1]) != 0)) { printf("Invalid Directory Name: %s\n", selp->a[1]); cexit(); } execv(selp->a[2], &selp->a[2]); printf("* Execute Error in Menu Selection *\n"); cexit(); } /* parent */ wait(status); signal(2, onintr); /* re-enable */ } reprint: ; printf("%s", bufr); /* print header */ /* print choices */ for (ii=0; ii/dev/line_out .sp In similar manner, some delays in your system may not let you use a 300 baud terminal to receive from another system. Keep in mind that the remote system will expect you to receive their asynchronous output at full rate. If you introduce swapping or carriage-return delays locally, you may fall behind if your local terminal is running at 300 baud... the answer is to use a higher speed output device or do delay-timing at the remote computer. .sh AUTHOR Neil P. Groundwater, Analytic Disciplines Inc, Vienna, VA. qa/*yz 0 4/adi/tcom.c# /* * tcom - transparent terminal communications * * Contributed to USENIX, February, 1980. * Please refer questions and any bugs to: * Neil Groundwater * c/o Analytic Disciplines, Inc. * 8320 Old Courthouse Road #300 * Vienna, Virginia 22180 * (703) 893-6140 * Credit for the original concept goes to the University of Waterloo. * * Compiled by: cc -O tcom.c * * Calling conventions: * tcom (communicate with full-duplex remote) * tcom anyarg (communicate with half-duplex remote) * tcom ^ tee msgfile ('record' terminal session) * tcom anyarg ^ tee msgfile (likewise) * */ #define DZ "/dev/ttye" /* local outgoing line */ #define BAUD300 ((7<<8) | 7) #define STOP 030 /* stops upon control-x */ #define ANYP 0300 #define RAW 0040 #define CRLF 0020 #define ECHO 0010 #define UC 0004 #define TABS 0002 #define HUPCL 0001 /* Version 1.4 */ main(argc, argv) char *argv[]; { int tty[3], rtty[3]; /* line modes */ int oldmode; /* to restore terminal later */ int rfd; /* file descriptor */ int parent, child; /* process id's */ char c; char anser[20]; if ((rfd = open (DZ, 2)) < 0) { printf("Cannot OPEN outgoing line!\n"); exit(-1); } printf("Connected!\r\n"); /* * The process probably needed to be super-user to OPEN * the outgoing line... INIT tends to leave them in unreadable * modes. Note the lack of protection for lines which * are in use by someone else however. * Anyway, super-user is no longer needed, so return to normal. */ setuid(getuid() & 0377); parent = getpid(); /* to allow child to kill upon it's death */ gtty(0, tty); /* set up local terminal */ oldmode = tty[2]; /* save for later */ /* fix up the terminal mode... 'delay' stuff is in the hi-byte */ tty[2] =& 0177400+ANYP+CRLF+UC; tty[2] =| RAW; /* * if an argument was supplied, set up to provide local echo. */ if (argc > 1) tty[2] =| ECHO; stty(0, tty); /* new mode installed */ gtty(rfd, rtty); rtty[0] = BAUD300; rtty[2] = ANYP+RAW+HUPCL; stty(rfd, rtty); /* * A child process is created to read the remote line * and route input to the local terminal. The parent * reads the local terminal and forwards output to the * remote line until EOF (the STOP char) is encountered. */ if (child = fork()) { /* parent */ for(;;) { if ((read(0, &c, 1) <= 0) || c==STOP) { tty[2] = oldmode; stty(0, tty); printf("\nShall I hang up the phone? "); if (read(0, anser, 20) > 0) if (anser[0] == 'n') { /* no HUPCL */ rtty[2] =& ~HUPCL; stty(rfd, rtty); } kill(child, 1); exit(0); } write(rfd, &c, 1); } } else { /* child */ for(;;) { if (read(rfd, &c, 1) <= 0) { printf("DISCONNECTED!\n\r"); tty[2] = oldmode; stty(0, tty); kill(parent, 1); exit(-1); } write(1, &c, 1); } } } q`/A\4/ecm2cq_/5j4/ecm2/install_notes All of the programs and object modules for keyio are contained in this directory. The programs are as follows: keyio.c - keyio I/O routines setup.c - keyio file setup program refresh.c - keyio file refresher kchk.c - dcb file check program keyio.n - keyio manual page The object file keyio.o should be placed into a system library so it may be referred to as the "-lK" option on a compile or load command. The programs setup, refresh, and kchk should be installed as system commands on /bin. The manual page can be put along with the other on-line manual pages. A sample program 'note' which uses keyio has been included. We would appreciate any user who installs and uses keyio to write us and let us know the type of machine keyio is being used on and how the installation went. This will also allow us to maintain a mailing list to notify users of new versions of keyio which can be expected from time to time. If there are any problems installing keyio, or, if you have any suggestions for improvement or enhancement please feel free to call or write me. Steve Saper Albert Einstein College of Medicine 1300 Morris Park Avenue Bronx, New York 10461 yqY,5j 4/ecm2/kchkG6  &6  w Z\%_  _55@ @mfe  @ @mfe  fe  fe   fe @ 5%  fe @ 5% @ @m\f X%e fef X% @m1@m1Ne  1|vpj  Xe N^XG eNm  u-_DN *N *w wrw wDe~   % w7 7 ׯ-   Hw7  . 6wB J7    ӕ-    ӕ- f&E ? r@A r  f  e0 9e   ҋ D~  x&  m  ~    ~ _7  | x0   dWp `e0eӕ?w DCӋ @wf. ,$P   @f  7 - wX~w:lhw@& BFF7Jyesnocommand is: kchk keyio_file(s) .dcb.key can't open dcb or key file for"%s" Current dcb values for file "%s" Record length %8d Key length %8d Records %8D Next address %8D Need to refresh %8s Deleted records %8s `dnlsFocrDLJORxVXfe>rnuUq]5j 4/ecm2/kchk.c/* * This program will enable the user to look at the current dcb * values for the specified keyio file. * * Written by Steve Saper * AECOM February 1980 * */ #include "keyio.h" #define MAXFILE 14 /* length of dcb file array */ #define MAXKEY 42 /* length of a key record */ #define DCB ".dcb" #define KEY ".key" #define ONE '1' char YES[] {"yes"}; char NO[] {"no"}; main(argc,argv) int argc; char *argv[]; { int fp, fp1, lrecl, keyl, i=1; long nrecs, dadd; char *msg, *dmsg, file[MAXFILE], file1[MAXFILE], keybuf[MAXKEY]; /* need at least one file */ if(argc==1){ printf("command is: kchk keyio_file(s)\n"); exit(-1);} /* for each file passed as an argument */ while(i < argc){ /* prepare the dcb and keyfile names */ file[0]=0; file1[0]=0; strcat(file,argv[i]); strcat(file1,argv[i]); strcat(file,DCB); strcat(file1,KEY); /* open dcb file */ if ( (fp=open(file,0)) == -1 || (fp1=open(file1,0)) == -1) printf("\ncan't open dcb or key file for\"%s\"\n", argv[i]); else { /* read the dcb file information */ read(fp, &dcbrec, sizeof (struct dcbrec)); /* search to see if there are any deleted records */ /* in the key file */ dmsg=NO; while( read(fp1,keybuf,dcbrec.keyl+11) ) if(keybuf[dcbrec.keyl] == ONE) break; if(keybuf[dcbrec.keyl] == ONE) dmsg=YES; /* print out the values */ printf("\nCurrent dcb values for file \"%s\"\n",file); msg=NO; if(dcbrec.openflag=='1') msg=YES; printf("Record length\t%8d\nKey length\t%8d\nRecords\t\t%8D\n", dcbrec.lrecl-1, dcbrec.keyl, dcbrec.nrecs); printf("Next address\t%8D\nNeed to refresh\t%8s\n", dcbrec.dadd,msg); printf("Deleted records\t%8s\n", dmsg); } i++; } close(fp); close(fp1); } q\5j94/ecm2/keyio.cn/* * Keyio - perform keyed access of files. Used to read, write, replace, * and delete keyed records in a special keyio format file. * * Written by Steve Saper * AECOM July 1979 ad infinitum * */ #include "keyio.h", long recs[MAXFILS]; /* number of non overflow key records */ long lastad[MAXFILS]; /* last read address */ long pointer; /* read or write address */ long daddr[MAXFILS]; /* last address in data file */ long offset; /* address of last key record */ int ovrflw[MAXFILS]; /* number of overflow keys */ int keyl[MAXFILS]; /* length of keys */ int lrecl[MAXFILS]; /* logical record length of data */ int nfils; /* number of open files */ int dpt[MAXFILS]; /* data file pointers */ int kpt[MAXFILS]; /* key file pointers */ int index; /* open file index number */ int maxovr[MAXFILS]; /* number of overflow keys */ char keyrec[KRECL]; /* record of matched key */ char keyovr[KEYOVR]; /* in core key overflow array */ char dlist[] {" "}; char lastkey[SIZLST]; /* last read key list */ char NEWLINE='\n'; char ONE='1'; char BLANK=' '; char ZERO='0'; char dkey[] {".key"}; char ddcb[] {".dcb"}; char SORT[] {"/bin/sort"}; char tmpd[] {"tmpd"}; char tmpk[] {"tmpk"}; /* this routine appends characters to the end of a string */ kapp( str1, str2) char str1[],str2[]; { int i,j = 0; i = kfblk( str1, FILELN); for(; str2[j]; j++, i++) str1[i] = str2[j]; str1[i] = 0; } /* this routine fills a buffer with blanks */ kblkfl( str, length) char *str; int length; { int i; for(i = 0; i < length & *str != NEWLINE & *str != 0 ; i++, *str++); for(; i < length; i++, *str++) *str = BLANK; return; } /* this routine checks whether a file is in the open list */ kcknm( fname ) char fname[]; { int i,j,k; index = -1; for(i = 0; i < MAXFILS; i++){ if(dlist[i * FILELN] == BLANK && index == -1) index=i; j = kcmpre( fname, dlist, FILELN, 0, i * FILELN); if(j == 0) { index = i; return(j); } } return(MNYFILS); } /* this routine compares two strings. if they are equal a value of zero */ /* is returned. if the first is greater a one is returned, if the second */ /* is greater, a two is returned */ kcmpre( str1, str2, length, st1, st2) char str1[],str2[]; int length,st1,st2; { int i,j,k; for(i = st1, j = st2, k = 0; k str2[j]) return(MNYFILS); } return(SUCCESS); } /* this routine copies one string to another */ kcpy( str1, str2, length, st1, st2) char str1[],str2[]; int length,st1,st2; { int i; for(i = 0; i < length; i++, st1++, st2++) str1[st1] = str2[st2]; return; } /* this routine finds the first blank char in a string */ kfblk( str, length) char str[]; int length; { int i; for(i = 0; i < length && str[i] != BLANK; i++); if(i < length) return(i); else return(length); } /* this routine adds an eight character filename to the open list */ kputnm(fname) char *fname; { int i; for (i = index *FILELN; i < (index*FILELN) + FILELN; i++, *fname++) dlist[i] = *fname; nfils++; return; } /* this routine opens a file for keyed i/o */ kopen(file) char *file; { long dadd,rec; int dp,kp,i,j,k,dcp; int lrec,key; char name1[FILBUF],name2[FDKLEN]; kcpy( name1, file, FILELN, 0, 0); kblkfl( name1, FILELN); /* too many files are open */ if(nfils == MAXFILS) return(MNYFILS); /* see if file passed is already open */ if(kcknm(name1) == 0) return(NOWOPN); /* open the new file */ if((dp = open( file ,2)) == -1) return(NODATA); /* open the key file */ kcpy( name2, name1, FILELN, 0, 0); kapp( name2, dkey); if((kp = open( name2, 2)) == -1) return(NOKEY); /* open the dcb file */ kcpy( name2, name1, FILELN, 0, 0); kapp( name2, ddcb); if((dcp = open( name2, 2)) == -1) return(NODCB); /* get the dcb info */ read( dcp, &dcbrec, sizeof (struct dcbrec) ); if(dcbrec.openflag == ONE) return(NOPEN); /* get the dcb info */ lrecl[index] = dcbrec.lrecl; keyl[index] = dcbrec.keyl; recs[index] = dcbrec.nrecs; daddr[index] = dcbrec.dadd; maxovr[index] = KCORE/keyl[index]; /* put file pointers in list */ dpt[index] = dp; kpt[index] = kp; /* put file name in open list */ kputnm(name1); /* set flag in file to protect open status */ dcbrec.openflag = ONE; lseek( dcp, 0L, 0); write( dcp, &dcbrec, sizeof (struct dcbrec) ); close(dcp); return(SUCCESS); } /* this routine writes a record in a file */ kput( pt, offset, buffer, recln, pos) long offset; int pt,recln,pos; char *buffer; { lseek( pt, offset, pos); write( pt, buffer, recln); return; } /* this routine seeks and gets a record from a file */ kget( pt, offset, buffer, recln) long offset; int pt,recln; char buffer[]; { lseek( pt, offset, 0); read( pt, buffer, recln); return; } /* this routine performs a binary search on the key file */ ksrch(key) char key[]; { long low,high,krec; int i,krecl; krecl = keyl[index] + 11; low = 1L; high=recs[index]; for(i = 0; i < MAXKEY; i++) keyrec[i] = BLANK; while(low <= high){ krec = (low + high) / 2; offset = (krec - 1) * krecl; /* seek to position and examine the key */ kget( kpt[index], offset, keyrec, krecl); i = kcmpre( key, keyrec, keyl[index], 0, 0); if(i == -1) high = krec - 1; else if(i == 1) low = krec + 1; else return(SUCCESS); } return(NOREC); } /* this routine gets the data file pointer from the key record */ kgetpt(buffer) char buffer[]; { int i = 0; pointer = 0L; while( buffer[keyl[index] + i + 1] != NEWLINE) { if(buffer[keyl[index] + i + 1] != BLANK) pointer = pointer * 10 + buffer[keyl[index] + i + 1] - ZERO; i++;} return; } kread( file, key, buffer) char *file,*key,*buffer; { int i; char fname[FILBUF],key1[MAXKEY]; /* see if the file is open */ kcpy( fname, file, FILELN, 0, 0); kblkfl( fname, FILELN); if(kcknm(fname) == 1) return(NOTOPN); /* look for key */ i = ksrch(key); if(i == 6 && ovrflw[index] == 0) return(NOREC); else if(i == 6) i = kover(key); /* get record pointer read record store last key */ /* first see if record was deleted */ if(i == 0){ if (keyrec[keyl[index]] == ONE) return(RECDEL); kgetpt(keyrec); kget( dpt[index], pointer, buffer, lrecl[index] -1); kcpy( lastkey, keyrec, keyl[index], index*MAXKEY, 0); lastad[index] = pointer; return(SUCCESS); } return(NOREC); } /* this routine scans an overflow area for the key in question */ kover(key) char key[]; { long pt; int kl,krecl,kp,i,j; kl = keyl[index]; krecl = kl + 11; kp = kpt[index]; /* read through the overflow area and check out the records */ for(i = 0; i < ovrflw[index]; i++){ if (kcmpre( key, keyovr, kl, 0, (index * KCORE + i * kl)) == 0){ /* read key record ... update offset pointer */ offset = pt = (recs[index] + i) * krecl; lseek( kp, pt, 0); j=read( kp, keyrec, krecl); if (j == 0) return(NOREC); if (j == -1) return(RDERR); return(SUCCESS);} } return(NOREC); } /* this routine closes an open file */ kclose(file) char *file; { int i,dp; char fname[FDKLEN]; kcpy( fname, file, FILELN, 0, 0); kblkfl( fname, FILELN); /* is the file open */ if(kcknm( fname, dlist) != 0) return(NOTOPN); /* zap out the open file name */ for(i = 0; i < FILELN; i++) dlist[index * FILELN] = BLANK; /* close the data and the key files */ close(kpt[index]); close(dpt[index]); /* sort the key file if updates were made */ if(ovrflw[index] != 0) ksort(file); /* open the dcb file */ kapp( fname, ddcb); dp=open( fname, 2); /* update the dcb file */ read(dp, &dcbrec, sizeof (struct dcbrec) ); dcbrec.nrecs = recs[index] + ovrflw[index]; dcbrec.dadd = daddr[index]; dcbrec.openflag = BLANK; kpt[index] = -1; dpt[index] = -1; ovrflw[index] = 0; nfils--; lseek(dp, 0L, 0); write(dp, &dcbrec, sizeof (struct dcbrec) ); close(dp); return(SUCCESS); } /* this routine puts the long integer data file pointer in the key record */ /* by encoding it onto a character string */ kputpt( buffer, lng, start) char buffer[]; long lng; int start; { int i = 8; long l; char temp[9]; l = lng; if(l == 0L) temp[i--] = ZERO; while(l){ temp[i--] = l % 10 + ZERO; l = l / 10;} while(i >= 0) temp[i--]=BLANK; kcpy( buffer, temp, 9, start, 0); keyrec[keyl[index] + 10] = NEWLINE; return; } /* this routine writes a record to the data file only if the record */ /* does not already exist. the key file is updated with the new key */ kwrite( file, key, buffer) char *file,*key,*buffer; { int lr,ret,klen,krecl,i; char fname[FILBUF]; kcpy( fname, file, FILELN, 0, 0); kblkfl( fname, FILELN); /* see if the file is opened */ if (kcknm( fname, dlist) == 1) return(NOTOPN); lr = lrecl[index]; klen = keyl[index]; krecl = klen + 11; /* see if the key already exists. if so dont write record */ ret = ksrch(key); if(ret == 6 && ovrflw[index] > 0) ret = kover(key); if (ret == 0 && keyrec[klen] != ONE) return(RECTHR); /* put the key in the keyfile */ kcpy( keyrec, key, klen, 0, 0); keyrec[klen] = BLANK; kputpt( keyrec, daddr[index], (keyl[index] + 1)); lastad[index] = daddr[index]; daddr[index]+ = lrecl[index]; kput( kpt[index], 0L, keyrec, krecl, 2); /* write record out to data file */ kput( dpt[index], 0L, buffer, lr - 1, 2); kput( dpt[index], 0L, &NEWLINE, 1, 2); /* update overflow counter */ ovrflw[index]++; /* put the last key in the list */ kcpy( lastkey, key, klen, index*MAXKEY, 0); /* check whether to resort the key file */ if (ovrflw[index] > maxovr[index]){ ksort(file); recs[index]+ = ovrflw[index]; ovrflw[index] = 0;} else kcpy( keyovr, key, klen, (index * KCORE+(ovrflw[index] -1) * klen), 0); return(SUCCESS); } /* this routine sorts the key file in ascending key order */ ksort(file) char *file; { char fname[FDKLEN]; int i; kcpy( fname, file, FILELN, 0, 0); kblkfl( fname, FILELN); kapp( fname, dkey); i = fork(); if(i == 0){ execl( SORT, SORT, "-o", fname, fname, 0);} while(wait0() != i); return(SUCCESS); } /* this routine replaces a record which was previously read in */ krepl( file, key, buffer) char *file,*key,*buffer; { int klen,i,j,lr; char fname[FILBUF],tempkey[MAXKEY]; /* see if the file is open */ kcpy( fname, file, FILELN, 0, 0); kblkfl( fname, FILELN); if (kcknm( fname, dlist) == 1) return(NOTOPN); klen = keyl[index]; lr = lrecl[index]; /* see if the record being replaced is the same as the last record read */ /* in. if so we already have the address of the data record */ kcpy( tempkey, lastkey, klen, 0, index * MAXKEY); i = kcmpre(key,tempkey,klen,0,0); if (i == 0){ kput( dpt[index], lastad[index], buffer, lrecl[index] - 1, 0); return(SUCCESS); } /* see if the key exists */ i = ksrch(key); if(i == 6 && ovrflw[index] == 0) return(NOREC); else if(i == 6) i = kover(key); /* see if record not deleted. if not, replace */ if(i == 0) { if(keyrec[klen] == ONE) return(RECDEL); kgetpt(keyrec); kput( dpt[index], pointer, buffer, lrecl[index] - 1, 0); lastad[index] = pointer; kcpy( lastkey, key, klen,index * MAXKEY, 0); return(SUCCESS); } return(NOREC); } /* this record deletes a record from the data file */ kdele( file, key) char *file,*key; { int klen,i; char fname[FILBUF]; kcpy( fname, file, FILELN, 0, 0); kblkfl( fname, FILELN); if (kcknm( fname, dlist) == 1) return(NOTOPN); klen = keyl[index]; /* see if the key we look for exists. if it does and it has not been */ /* previously deleted, flag it for deletion */ i = ksrch(key); if(i == 6 && ovrflw[index] == 0) return(NOREC); else if(i == 6) i = kover(key); /*see if record already deleted. if not delete it */ if(i == 0) { if(keyrec[klen] == ONE) return(RECDEL); keyrec[klen] = ONE; kput( kpt[index], offset, keyrec,klen + 11, 0); return(SUCCESS); } return(NOREC); } /* this routine reads a keyed file sequentially */ kseq( file, key, buffer, start) int start; char *file,*key,*buffer; { int i,klen; char fname[FILBUF],keyrec[KRECL]; long off; /* see if the file is open */ kcpy( fname, file, FILELN, 0, 0); kblkfl( fname, FILELN); if(kcknm( fname, dlist) == 1) return(NOTOPN); /* see if key file was sorted */ if (ovrflw[index] != 0) return(CLSFIR); klen = keyl[index]; /* see if start value is o.k. */ /* beginning=0 previous record = -1 present loc=1 last record = 2 */ if(start < -1 || start > 2) return(BADST); if(start == 0) lseek( kpt[index], 0L, 0); else if(start == 2){ off = -(klen + 11); lseek( kpt[index], off, 2);} /* sequentially read a record */ keyrec[klen] = ONE; /* read until non deleted record */ while(keyrec[klen] == ONE){ if(start == -1) { off= -2 * ( klen + 11); lseek( kpt[index], off, 1);} i=read( kpt[index], keyrec, klen + 11); if(i == 0) return(SEQEOF); } /* put the key in buffer */ kcpy( key, keyrec, klen, 0, 0); /* get the data record */ kgetpt(keyrec); kget( dpt[index], pointer, buffer, lrecl[index] - 1); /* enter in the last key and address */ kcpy( lastkey, key, klen, index * MAXKEY, 0); lastad[index] = pointer; return(SUCCESS); } Fkopen(file,err) char *file; int *err; { int i; char fname[FILBUF]; i=kfblk(file,FILELN+1); kcpy(fname,file,i,0,0); fname[i]=0; *err=kopen(fname); } Fkread(file,key,buffer,err) char *file,*key,*buffer; int *err; { int i; char fname[FILBUF]; i=kfblk(file,FILELN+1); kcpy(fname,file,i,0,0); fname[i]=0; *err=kread(fname,key,buffer); } Fkclose(file,err) char *file; int *err; { int i; char fname[FILBUF]; i=kfblk(file,FILELN+1); kcpy(fname,file,i,0,0); fname[i]=0; *err=kclose(fname); } Fkwrite(file,key,buffer,err) char *file,*key,*buffer; int *err; { int i; char fname[FILBUF]; i=kfblk(file,FILELN+1); kcpy(fname,file,i,0,0); fname[i]=0; *err=kwrite(fname,key,buffer); return; } Fkrepl(file,key,buffer,err) char *file,*key,*buffer; int *err; { int i; char fname[FILBUF]; i=kfblk(file,FILELN+1); kcpy(fname,file,i,0,0); fname[i]=0; *err=krepl(fname,key,buffer); return; } /* this record deletes a record from the data file */ Fkdele(file,key,err) char *file,*key; int *err; { int i; char fname[FILBUF]; i=kfblk(file,FILELN+1); kcpy(fname,file,i,0,0); fname[i]=0; *err=kdele(fname,key); return; } Fkseq(file,key,buffer,start,err) char *file,*key,*buffer; int *start,*err; { int i, st; char fname[FILBUF]; i=kfblk(file,FILELN+1); kcpy(fname,file,i,0,0); fname[i]=0; st = *start; *err=kseq(fname,key,buffer,st); return; } eq[ڃ5j 4/ecm2/keyio.hn#define MAXFILS 5 /* maximum number of keyed files */ #define FILELN 8 /* length of file name */ #define FILBUF 9 /* size of array containing file name */ #define FDKLEN 13 /* size of array containing dcb or key file name */ #define KRECL 44 #define SIZLST 160 #define KEYOVR 7750 /* size of overflow core buffer */ #define KCORE 1550 /* size of one files overflow buffer */ #define MAXREC 16500 /* maximum record length */ #define MAXKEY 31 /* maximum key length */ #define SUCCESS 0 /* success on call */ #define SEQEOF -1 /* eof on kseq read */ #define MNYFILS 1 /* too many files opened */ #define NODATA 2 /* can't open data file */ #define NOKEY 3 /* can't open key file */ #define NOWOPN 4 /* file is already open */ #define NOTOPN 5 /* file is not open */ #define NOREC 6 /* no record for specified key */ #define RECDEL 7 /* record has been previously deleted */ #define BADST 8 /* bad kseq start value */ #define CLSFIR 9 /* must close before kseq call */ #define RECTHR 11 /* record exists can't create */ #define NODCB 13 /* cannot open dcbfile */ #define BADLREC 14 /* record length too long */ #define NOPEN 15 /* cannot open file */ #define RDERR 16 /* read error */ #define BADKEYL 17 /* key length too long */ #define FILTHR 18 /* file already exists */ struct dcbrec { int lrecl; /* record length, includes 1 extra byte for a \n */ int keyl; /* key length */ long nrecs; /* number of records in file */ long dadd; /* address of next data record */ char openflag; /* open status byte */ } dcbrec; /* from accessing file */ qIƒ5jQ4/ecm2/keyio.nn.th keyio local 7/7/79 .sh NAME keyio \*- perform keyed I/O .sh DESCRIPTION .it Keyio is a series of routines which will perform keyed access on files. In order for the routines to properly function, the keyio files must exist in the working directory. The key length and record length within a file are fixed . The routines are available from C and as Fortran subroutines. A description of the variables used and the routines follows. .s3 .ti 22 Variables .ti 22 --------- .s3 .lp +10 10 .bn file The name of a data file (1 to 8 characters left justified, null terminated in C, blank terminated in Fortran). .ti 22 C - char *file; .ti 22 F - integer array .s3 .lp +10 10 .bn keyl The length of each key in bytes (maximum is 31). .s3 .lp +10 10 .bn lrecl The length of each data record (maximum is 16499 bytes). .s3 .lp +10 10 .bn status A two byte integer to receive the completion code of a Fortran keyio call. .ti 22 F - integer*2 status .s3 .lp +10 10 .bn key A byte string of length 'keyl' which uniquely identifies the record being processed. .ti 22 C - char *key; .ti 22 F - integer array .s3 .lp +10 10 .bn buffer The data record which is being processed in 'file'. It contains as many bytes as the record length specified for the file being used. .ti 22 C - char *buffer; .ti 22 F - integer array .s3 .lp +10 10 .bn start This is used to specify the starting location of a sequential read (see kseq). .ti 22 C - int start .ti 22 F - integer*2 start .s3 .ti 22 Keyio Utilities .ti 22 -------------- .s3 .lp +10 10 .bn setup \- Files being used by keyio are declared through this system command. The format of the command is: .ti 22 setup file keyl lrecl .s3 Upon a successful completion of this command, the data file is created along with a key file and a dcb file with the names: .ti 22 .bn "file " \- data file .ti 22 .bn file.key \- key file .ti 22 .bn file.dcb \- dcb file Precaution must be taken as to not delete or modify the files outside of the keyio routines or serious loss of data may occur. .s3 .lp +10 10 .bn refresh \- This system command is used to remedy the following situations: 1). A file was not closed due to a program/system crash or a programmer error and cannot be opened. 2). Many records in a file were deleted and it is desired to shrink the size of the file. The format of the command is: .ti 22 refresh [-r] [-k] file .ti 27 -r - the refresh will only remedy \'1\' .ti 27 above (default is to fix both \'1\' and .ti 27 \'2\' above). .s3 .ti 27 -k - keep a copy of the old data, .ti 27 key, and dcb files named as .ti 27 file[.key][.dcb].bak .s3 .lp +10 10 .bn kchk \- This system command will print the information contained in the dcb files for the keyio files specified in the argument list. The output is self explanatory. The format of the command is: .ti 22 kchk file1 file2 file3 ... .s3 .ti 22 Keyio Routines .ti 22 -------------- .lp +10 10 .bn kopen \- In order to use a file for keyed access, it must be explicitly opened. This is done through the kopen call in the format: .ti 22 C - kopen(file) .ti 22 F - call kopen(file,status) .ti 15 Keyio allows a maximum of five files to be opened simultaneously for keyed access. If more than five files are needed, an open file must be closed and then another file can be opened. .lp +10 10 .bn kwrite \- The writing of keyed records to the data files are performed with the kwrite call. The format of the call is: .ti 22 C - kwrite(file,key,buffer) .ti 22 F - call kwrite(file,key,buffer,status) .ti 15 Only unique keys can be used successfully with the kwrite routine. To write records with a key that already exists, see the 'krepl' routine. .lp +10 10 .bn kread \- This routine is used to read a record from a data file by specifying the key of the record. The format of the call is: .ti 22 C - kread(file,key,buffer) .ti 22 F - call kread(file,key,buffer,status) .ti 15 Following successful completion of the kread call, the data record is in 'buffer'. Buffer is unmodified if kread fails. .lp +10 10 .bn krepl \- To replace a non-deleted record in the data file the krepl routine is used. The format of the call is: .ti 22 C - krepl(file,key,buffer) .ti 22 F - call krepl(file,key,buffer,status) .lp +10 10 .bn kseq \- When it is desired to process the data in sequential key order, this routine is called. The format of the call is: .ti 22 C - kseq(file,key,buffer,start) .ti 22 F - call kseq(file,key,buffer,start,status) .ti 15 The value of 'start' determines where sequential reading will begin. These values are: .ti 22 0 - read the first record .ti 22 -1 - read the previous record .ti 22 1 - read the next record .ti 22 2 - read the last record The result of a call to kseq is that the next non-deleted key and the corresponding data record are returned. It is possible to obtain a record with kread and then sequentially process from that point on with kseq. A file on which kseq is being used must have its' keys in sorted order. If kwrite was used on a file since it was opened the file must first be closed to cause sorting to occur, and then reopened in order to perform sequential processing. .lp +10 10 .bn kdele \- To delete a record from the data file this routine is called with the format: .ti 22 C - kdele(file,key) .ti 22 F - call kdele(file,key,status) .ti 15 A successful call to this routine marks 'key' for deletion from the key file. Both the key and the associated data record actually remain in the file until they are removed by the refresh routine. .lp +10 10 .bn kclose \- When the processing of a file has ended it must be closed. This is done through the kclose routine. The format of the call is: .ti 22 C - kclose(file) .ti 22 F - call kclose(file,status) If a file is not closed, or, if a program aborts before a file can be closed, it will not be possible to reopen the file. In order to remedy this situation see refresh. .s3 .ti 22 Keyio Status Codes .ti 22 ------------------ .ti 22 All of the C routines return a 2 byte .ti 22 integer status code. The same code is .ti 22 returned via the last argument in the .ti 22 Fortran calls. .ti 16 -1 EOF (end of file) on data file during kseq .ti 22 call. .ti 16 0 Success. .ti 16 1 Too many files open. .ti 16 2 Can not open data file. .ti 16 3 Can not open key file. .ti 16 4 File is already open. .ti 16 5 File is not open. .ti 16 6 No record found for key. .ti 16 7 Record has been previously deleted. .ti 16 8 Invalid KSEQ start value. .ti 16 9 Must close file first and then reopen .ti 16 to use kseq call. .ti 16 11 Record exists cannot create. .ti 16 13 Cannot open dcbfile. .ti 16 14 Record length too long. .ti 16 15 Cannot open file. .ti 16 16 Read error. .ti 16 17 Key length too long. .ti 16 18 File already exists. .ti 22 Keyio Access .ti 22 ------------ In order to use keyio, it must be loaded with the program being run. On the compile or load command include the option -lK as the first library that is to be searched. If the program that is being loaded is very large, include the -s, -x and -i options on the load command. Please address all comments and suggestions to Steve Saper, AECOM Scientific Computing. oqHm̓5j94/ecm2/keyio.onGXXw 5 f  5 @@mAAmH @@mȋ@@mww 5  u- A @@ @0 @ u-  @ w>w :05 @tX%w@t& Xf 4e5ww %w u u 5 !@@mAAmHw@@mAAmH u- w ` 5 @@m AAm H u-w.w * 5 @@mȭ u-u-@w@w t5 @pX @ te@- ww 0 & ffe efe T %v w`Ne f 5% & fefe efe fe 5% & fefe efe fe 5% f %~ xr nftd\RtTL>  2 r$ p pNe   & f ef %N _w Nfff eN f f %ww  fff eN f f %wlw h` e 5 Dt555 @ %u-su-n A@@mAm@ f& e5uf A@ f& e7wN & de &  &f 4e5% A@ 5u% A@e@ 5u w,w " 5 7 7 3 @m@m$  e CmCmÜ `@ `ÝH 7w  @m@mww , & ffe efe T Ne % B w2N 5%%N 5  |    f & de Wpf & et w xp 5@e 5X 55 wB%  . p-M WpCp`N& ff 4e f tC `@ `f& eu57w fff eNf %5w  & ffe efe T Xfe w65 .t X %     N  fe fe 5f %t  `@ `7wt77~ zj ^ R 0 H & f ef %N _w uu 0 -@@an $ ff eL `BBar  ff e5u  @@a  f  fef eR  wBw > & ffe efe T Xfe %w 5 5@e 5N 5%  N 5 @   & ff e@f  Xtf& e8t(tr2 A  tr`r 2`f&  & 2e f f&  & 2e &  & 2e   Wpfff ef ` p,N  J A >tr`r 2`* 0  Wp  p`fff e _ w  & ffe efe T fe 5 fefe e x@- wlw h2 & ffe efe T Xfe %w 5 5WpN& ffe e & ffef 4e5   &ftf& & 2e N 5% n %N 5 @  &  &f & 2e t Wpfff ew  & ffe efe T Xfe % v wfb 5N 5%%N 5 @@ fe  & 2e w > & ffe efe T Xfe %  w z 5% %   & % @e 5 ff* & e@@m@@m3% Ae Wp@5 ff & eNe fe & %5 & ffef eNe t  fd^Z & de FWpfff e(t" _rw   f  5 & fffe e@@m0Ne R=ww  f  5 & fffe e@@m0Nffe r%= whw d  f  5 & fffe e@@m0Ne |=ww   f  5 & fffe e@@m0Nffe %= ww  f  5 & fffe e@@m0Nffe %= wdw `  f  5 & fffe e@@m0Nfe 8 =ww  f  5 & fffe e@@m0u Nfffe e= w 1 0.key.dcb/bin/sorttmpdtmpk-oYYYYYYYY x   H Hx YYx YYYYxY99x99 x99xYhYx99x9(9(xYh YYYhh H H  h  xYYxhxHHHH((HHHhhhhhHYYYx((h999(9(hYxYYYhx999(9(YYYYYYY_dcbrec _recs _lastad _pointer _daddr _offset _ovrflw _keyl _lrecl _nfils _dpt _kpt _index _maxovr _keyrec ,_keyovr F_dlist#X_lastkey _NEWLINE#_ONE#_BLANK#_ZERO#_dkey#_ddcb#_SORT#_tmpd#_tmpk#_kapp"~kappcsv str1str2ij_kfblk"L10:L20001 cret _kblkfl"T~kblkflTstrlengthiL16^L10000jL10001nL10002zL10003~L10004L10005L19L15_kcknm"~kcknmfnameijkL20003L28_kcmpre"4L27"L24~kcmpre4str1str2lengthst1 st2 ijkL33L20007NL36pL32lL20005h_kcpy"~kcpystr1str2lengthst1 st2 iL41L20009~kfblkstrlengthiL47L20011L48L50L46_kputnm"~kputnmfnameiL548L20013"_kopen"R~kopenRfiledaddrecdpkpijkdcplreckeyname1name2L60L59L20015L20017_open L63L64^_read L65~_lseek _write _close _kput"2~kput2ptoffsetbuffer recln pos_kget"d~kgetdptoffsetbuffer recln _ksrch"~ksrchkeylowhighkrecikreclL20019L78L79L10006ldiv lmul L80L82L74_kgetpt"~kgetptbufferiL87TL20021L89P_kread"r~kreadrfilekeybufferifnamekey1L93L92L20023L94L20024L95_kover"L97~koverkeyptklkreclkpijL101L20026L100L105L103L20029v_kclose"|~kclose|fileidpfnameL110L109L20031L114 _ksort" _kputpt" ~kputpt bufferlngstart iltempL119j L10007" lrem L121 L20034x _kwrite" ~kwrite filekeybufferlrretklenkreclifnameL126 L125 L127\ L128t L129 L130 ~ksort filefnamei_fork L136 L135_execl _wait0 _krepl" ~krepl filekeybufferklenijlrfnametempkeyL141 L140 L142|L20035xL143L20036L144L146_kdele"8~kdele8filekeyklenifnameL150L149L20038L151L20039L152L154_kseq"~kseqfilekeybufferstart iklenfnamekeyrecoffL158vL157rL20041hL10008nL161L20047L162L164L165dL166:_Fkopen"~Fkopenfileerrifname_Fkread">~Fkread>filekeybuffererr ifname_Fkclose"~Fkclosefileerrifname_Fkwrite"~Fkwritefilekeybuffererr ifname_Fkrepl"B~FkreplBfilekeybuffererr ifname_Fkdele"~Fkdelefilekeyerrifname_Fkseq"~Fkseqfilekeybufferstart err istfnameqG5j 14/ecm2/noteG-T$ &6  X'w l,5 -@& 4) ?-@& 4) 0-@& 4) !-@& 4)    &-@& 4) %%-  l'. .5$.  l'% % 0 4. fwj+w Z+1-=. H%e|0w v01-F. |%b0\0O.- leT. 5 ..E .~0 v 5%  %< @0@p1 @ 11-d. %w*w * v.- 4) 1-{. %1-m. >"e5%wL*w <*. Ne. n ff.- de-. N! 5. N. w)w )  . ) . 1 &5 !////. )e  P'@-$/ .7 .7 .1--/ %6/ fw^)w N) f&5 e/R/?/ )ew0) &@-w )Nef~0 %w)w (Neff %w(w (DA555  ԋNeffe %w(w (DC 5 5 /7+ y 5 %*5 %9 AWp `eu%0 0u%l %a %z e%[ d  0 ZNefff e    @%%@ @ EN v 5 %w'w x'P%c%s%[N f fff jewH'5 5 5 5 %A %Z e 5 %e%f  %o%xDe5 5 @ @ EN v % % % %-5 Ԑ@ @ EN v  1 A@  5u%_N  4 = _%+ @ _@ E %0%98%)%._%e%E %    Ԑ@ _@ Ee%a%f%A%F %A@v% A@v@mAm@ vA@v5u%0%90 %a%fW7 5`u`u C"% _$ _$ N v %+ %- %0_$%9_$Ԑ@ _vN v _ @e! _F  ff@} Ne p&=Ne p&=_Fw $DC = 5%c%0u5 %s E  v rn/%%c5 %[ rn/  E  v  % 4 =  D- %cw2# w #D ̥^  n/n/ %E%]  n/n/  w"w "0fef %w"w "BuNefef % = Ne&  @w^"w N"D - -  0 Z  |w"w "D0 Z@w! '4 eU4 && )%4 % 4 E & & Xe Ӌ 7r& h& ! ӕ- ӕ0B~F&ӕ.  ӕ0~ B~7$& & @! ӕ-ӕ.& B~ӕe ӕ- ӕ+ r e0e0Sw wIDIB %wI f& & e wV 7 |I7 |I xIׯlI- dI bIׯ\I00ZIwHI7 JI .|w>I(0Bw: J&I I _ I I o x d u H       ӕ- f&Ew Hӕ0 N r@A r  f  e0 9e' ) '@Hl0ҋ D~"HH H H 7Gw6G G Gff <e w7 G G G0   GWp `e0w RDCB &  z f   ̥-%0  : :  &   z f   ww D t0 Zufe& x*%4 :$%0U ) 22 '  & x*%R  w@w DE%& x*%  ww ~0 e- w|w lD  v) )4 ?4  w8w (DhE dE  ) ^)& x*%~ l'ww Nefef 5& ,e C ӕ-B  @@ % :%6 ӕ. `ȥ0  B- ӕe @ 5ӕ-ӕ+A r e0A r e0@* ӕ. ӕ0 B-ӕ. B- u-  ӕ0@ @-ӕ.@ww 5 f  5 @@mAAmH @@mȋ@@mw|w l 5  u- A @@ @0 @ u-  @ ww #5 @t~0%#w#@t& 0f e5w#w %w u u 5 !@@mAAmHwZ@@mAAmH u- w  5 @@m AAm H u-ww  5 @@mȭv u- @0 u-@w@w  "t5 @p0 @ p"te@- H"wdw T0 & ffe defe  % " wNe  f ) 5% & fefe de*1fe  fe ) 5% & fefe de01fe  fe ) 5% 6f )% *!  h6!  ^6!t 6 6 tz >6r <6  r6 pt6 p~6Ne P8  & f t'e6f x*%N v) _xw zNfff t'eN f f x*%wXw H fff t'eN f f )%w(w  ^6e 5 t56565 @x6 %u-su-n A@@mAm@ f& e5uf A@ f& e72w0N6$R &~6 :e & < &^66f e5% A@ 5u% A@e@ 5u ww  5 7 z7 x3 ^6@m@mL$ RL e ^6CmCmÜ `@ `Ý 7w Z ^6@m@mwJw :, & ffe defe  Ne %  T6w ^6f  N j5%%N n5  ^6266  h6 f f &t6 :e RWpfH &^66U de.t&6$6 w  5^6@e 5 5~65 w%   p-T6MWpCp`N& f6f e f t66C `@ `f& eu57"w  fff t'eN6f )%5w  & ffe defe  0fe  w5 tb0 % ~6 v) t6 v) T6N 01fe  fe ) 56f )%Lt66< T6 `@ `7w"t7<67>6 ~6 t6 0 T6  & f t'e6f x*%N v) _w uu 0 -@@a$ $ ff Fe`BBar  ff &e5u  @@a  f  fef de ^66ww  & ffe defe  0fe  %w ^6f  x 5h6l 5^6@e 5N j5% B T6N n5 @6  & ff6 de@6 ^6 t>6<6f&6 et>6<6tr&62$6 Ah6 tr`>6r <62`<6f6& r &~6 e @@mff& B &t6 e 0 T6 $WpfffU de  p,6T6N  AT6 tr`6r 62`6 0 T6 Wp T6 p`fff6 de _w  & ffe defe  *1fe  ` 5 fefeL16161 )e @- w w  2 & ffe defe  0fe  %w  ^6f   5^6 5h6WpN& fUfe de & ffef e5&@@m : h6 &f(t&6$6f& &t6 e N j5%  T6%N n5 @X6_6 @@m6  &h6f82~ &t6 e lt&6$6 VWpfffU dew 4  & ffe defe  0fe  %  T6w  5^6Nf  N j5%%N n5 @&6@6 fe 6.(\ &~6 e w D > & ffe defe  0fe  %  w  T6 5^6% %   & % @e 5 ff &~6 t'e@@m@@m3% Ae Wp@5 ff8 &~6 t'eNe fe &~6 )%5 & ffef deNe  h6 fxr &t6 :e WpfffU det6&6.$6 _"w p  f  5 & fffe de@@m0Ne .=w0w   f  5 & fffe de@@m0Nffe H%= ww   f  5 & fffe de@@m0Ne f=ww v  f  5 & fffe de@@m0Nffe %= w,w   f  5 & fffe de@@m0Nffe |%= ww   f  5 & fffe de@@m0Nfe N! =w|w l  f  5 & fffe de@@m0Nffe >"%= w"w Wf&  C% - 0    0  5  ע+ ע- 0 Wp `  BW@ &  w$ W B~  VVw>\ B@e w*w   %   N ff 2*%% @tAWtE@PN e&f 2*% wfEw BeEB- w~B @ E!-, -* ^1 x*% 25% `7 <- e5-7-5-D7e@5% 5 *% @5 *%-fe\@m7LDFB w dD7, w^w NDCԋ w>#w $Dԋ@ w we7~1ww7, 1 w1w1wm- ~1vp wr`\1 wTw 2 <&w> }w$w, 1wfA w,w"e"w"ew"@lw"Alew &@t`e w BC   @ C B Am @ @m wdw TC   @ C B Am@ @m CSw.w @w & CB    5 5   vA @ @-A-  A @ 5@  5  ww @w & B    5 5    vA @ @-A- A @ D5@ 5  Lww w @& BFF7)f5w  * f5w  }7 *)")W&fU 7 )@% (@A&@V7@L> Be0# @Uє V    BA   W Ve B@e0Um* z(` UeȐ9 ȕ0 Uȕ1 H( B(`0UUVVhead-a-d-p-r-scommand is 'note [-adprs]' notefileopen error #%d notefilenotefilenotefile%4ldEnter the note notefilenotefileheadNote #%4.4s : %sEnter the note to delete %ld%4ldnotefileNote deleted kdele error #%dnotefilecan't recreate file /local/bin/setup/local/bin/setupnotefile460notefilenotefilenotefile/local/bin/refresh/local/bin/refreshnotefile %scanf ungetc Reading bad file d o x f e gp c~ s l L u r D O X U(null)writing 440 1 0.key.dcb/bin/sorttmpdtmpk-oXc&zX1X1X1malloc: free storage corrupted V %ewJ> qF5j4/ecm2/note.c/* * note -adprs This program maintains user written messages which are * stored in a keyio format file. * Written by Steve Saper * AECOM January 1980 */ #include #define NOTEFILE "notefile" #define SETUP "/local/bin/setup" #define REFRESH "/local/bin/refresh" struct note { long key; char text[60]; } note; char key[] {"head"}; main(argc,argv) int argc; char *argv[]; { int flag,err=0,i; /* see what the option is */ if(strcmp(argv[1],"-a")==0) flag=1; else if(strcmp(argv[1],"-d")==0) flag=2; else if(strcmp(argv[1],"-p")==0) flag=3; else if(strcmp(argv[1],"-r")==0) { refresh(); exit();} else if(strcmp(argv[1],"-s")==0) { setup(); exit();} else err=1; if(argc<2 || err==1){ printf("command is 'note [-adprs]'\n"); exit(-1);} /* open the note file */ i=kopen(NOTEFILE); if(i!=0) { printf("open error #%d\n"); exit(-1);} if(flag==1) add(); else if(flag==2) delete(); else print(); kclose(NOTEFILE); } /* adds a record to the note file */ add() { int i,j; /* get the next key */ kread(NOTEFILE,key,¬e); note.key++; krepl(NOTEFILE,key,¬e); sprintf(key,"%4ld",note.key); printf("Enter the note\n"); for(i=0;i < 60 & (j=getchar())!='\n'; i++) note.text[i]=j; note.text[i]='\n'; kwrite(NOTEFILE,key,¬e); } /* this routine prints the notes */ print() { int i; while( (i=kseq(NOTEFILE,key,¬e,1))!=-1) if(strcmp(key,"head")!=0) printf("Note #%4.4s : %s",key,note.text); } /* this routine deletes a note */ delete() { int i; long tmp; printf("Enter the note to delete\n"); scanf("%ld",&tmp); sprintf(key,"%4ld",tmp); if( (i=kdele(NOTEFILE,key))==0) printf("Note deleted\n"); else printf("kdele error #%d",i); } /* this routine sets up the note file business */ setup() { int pid; if (open(NOTEFILE,0)>0) { printf("can't recreate file\n"); return;} pid=fork(); if(pid==0) { execl(SETUP,SETUP,NOTEFILE,"4","60",0); return(-1);} while(pid!=wait()); kopen(NOTEFILE); note.key=0L; kwrite(NOTEFILE,key,¬e); kclose(NOTEFILE); } /* this routine refreshes the note file */ refresh() { int pid; pid=fork(); if(pid==0){ execl(REFRESH,REFRESH,NOTEFILE,0); return(-1);} while(pid!=wait()); } qE5j4/ecm2/note.manUnable to locate article note in section cmd It is in [local]; proceeding ... note [local] 1/14/80 note [local] NAME note - maintain user notes SYNOPSIS _n_o_t_e -adprs DESCRIPTION _N_o_t_e provides an easy method for a user to write messages to him/herself. These notes can be printed at any time and/or can be looked at during login through the .profile.sh file (provided the note files reside in the users' login directo- ry). The command expects one of the following options. Options: -_a add a note (notes are up to 60 bytes long). -_d delete a note. -_p print all notes. -_r refresh the note file. This is used to correct any errors from the note command, or, to condense the note file after many notes have been deleted. -_s initialize the note file for subsequent use. FILES notefile notefile.dcb notefile.key SEE ALSO keyio[local] WARNING If any alteration is made to any of the note files, the command will not function properly. - 1 - qD5j$4/ecm2/refreshG*j &6  w %@ % Ar A @@Ak @0%, ~ X@ @mQ ~ % Ak @0v% Ar @0De@& P @& N 5%  N ~ w f f %  & f ef %5 @ @m 5 j_zw $ f N 5%w Nfe n fe P fe N 5%Nfe n fe P fe N 5% f f %      w w  & f eT f %N w  Nfff eN f f %w w  fff eN f f f %w w 5 7 7 -@m @m !   eCm CmÜ `@ `Ý| 7 w @m @mR w, w    t N ,f mP mN @ 7F wD 74 w2 > . : * & Nfe n fe P fe N 5f %N w w p uu 0 -@@at $ ff  eR `BBar  ff e5u  @@a 5 u @@mAAmH %  Hw w Nfe n fe P 5 fefe  e @- w> w . @N 5 % @0% @_7 L 7 J 7 L 7 J N @e 5B :        N 5 N 5]%_@@mNNe  fe*  f eN   fe Neffe& f e l fe*& f e e> w 8 H 7`6 w`4 w . Nfef f %5N N N N  _ZNfe n &fe P Nef  Nfe n fe P &fe P Nfe n fe P Nefe  Nfe n fe P Nfe n fe P &fe P 5 fefe  e  L@-N  Nfe n fe P Ne    N ww  ~5 ff    e  @-w w:w   %   N ff %% @tAWtE@PN e&f % w^fEw @wDe~   % w 7 7 ׯ-   Hw7  . 6wB J7v    ӕ-    ӕ- f&E ? r@A r  f  e0 9e   ҋ D~  x&  m  ~    ~ _ 7 \ R N0   :Wp `e0eӕ?w nDCӋ @w`w PDC@wHf ,P   @f  |7 |- wwe7ww72 wz~w^lh w@w  2&w* }w62wfA w,w"e"w"ew"@lw"Alew &@t`e w xBC   @ C B Am @ @m wZw JC   @ C B Am@ @m CSw$w @w & CB    5 5   vA @ @-A-  A @ 5@  5  ww @w & B    5 5    vA @ @-A- A @ D5@ 5  Lw @& BFF7 1 0.key.dcb/bin/sort/bin/mv/bin/cptmpdtmpk.bakcommand is 'refresh [-r] [-k] file' refresh on file %s .dcb** refresh complete ** -- keyio err#%d -- -o d" l s o c& D8 L O x X f e r" u8 U|  %ewqC5j4/ecm2/refresh.ct/* * refresh - will perform a keyio refresh. * Written by Steve Saper * AECOM July 1979 */ #include "keyio.h" long recs; /* number of non overflow key records */ long pointer; /* read or write address */ long daddr; /* last address in data file */ long offset; /* address of last key record */ int ovrflw; /* number of overflow keys */ int keyl; /* length of keys */ int lrecl; /* logical record length of data */ int dpt; /* data file pointers */ int kpt; /* key file pointers */ int kflag; char keyrec[KRECL]; /* record of matched key */ char NEWLINE='\n'; char ONE='1'; char BLANK=' '; char ZERO='0'; char dkey[] { ".key"}; char ddcb[] { ".dcb"}; char SORT[] { "/bin/sort"}; char MV[] { "/bin/mv"}; char CP[] { "/bin/cp"}; char tmpd[] { "tmpd"}; char tmpk[] { "tmpk"}; char bak[] { ".bak"}; main(num,arg) int num; char *arg[]; { int i,j; if(num==3) arg[1]++; if((num==3 & (*arg[1]!='r' & *arg[1]!='k')) || num==1) printf("command is 'refresh [-r] [-k] file'\n"); else { printf("refresh on file %s\n",arg[num-1]); if(num==3 & *arg[1]=='k') kflag=1; if(num==3 & *arg[1]=='r'){ strcat(arg[2],".dcb"); i=open(arg[2],2); if(i==(-1)) i=13; else { read(i,&dcbrec, sizeof (struct dcbrec) ); dcbrec.openflag = BLANK; lseek(i,0L,0); write(i,&dcbrec, sizeof (struct dcbrec) ); i=0;} } else i=kfresh(arg[num-1]); if(i==0) printf("** refresh complete **\n"); else printf("-- keyio err#%d --\n",i); } } /* this routine opens a file for keyed i/o */ kopen(file) char file[]; { int dp,kp,i,j,k,dcp; char name2[FDKLEN]; /* open the new file */ if((dp=open(file,2))==(-1)) return(NODATA); /* open the key file */ strcpy(name2,file); strcat(name2,dkey); if((kp=open(name2,2))==(-1)) return(NOKEY); /* open the dcb file */ strcpy(name2,file); strcat(name2,ddcb); if((dcp=open(name2,2))==(-1)) return(NODCB); /* get the dcb info */ read(dcp,&dcbrec,sizeof (struct dcbrec)); /* decode the dcb info */ lrecl=dcbrec.lrecl; keyl=dcbrec.keyl; recs=dcbrec.nrecs; daddr=dcbrec.dadd; /* put file pointers in list */ dpt=dp; kpt=kp; /* flag file for protect open status */ lseek(dcp,0L,0); dcbrec.openflag=ONE; write(dcp, &dcbrec, sizeof (struct dcbrec)); close(dcp); return(SUCCESS); } /* this routine writes a record in a file */ kput(pt,offset,buffer,recln,pos) long offset; int pt,recln,pos; char *buffer; { lseek(pt,offset,pos); write(pt,buffer,recln); return; } /* this routine seeks and gets a record from a file */ kget(pt,offset,buffer,recln) long offset; int pt,recln; char buffer[]; { lseek(pt,offset,0); read(pt,buffer,recln); return; } /* this routine gets the data file pointer from the key record */ kgetpt(buffer) char buffer[]; { int i=0; pointer=0L; while( buffer[keyl+i+1]!=NEWLINE) { if(buffer[keyl+i+1]!=BLANK) pointer=pointer*10 + buffer[keyl+i+1] - ZERO; i++;} return; } /* this routine closes an open file */ kclose(file) char file[]; { int i,dp; char fname[FDKLEN]; /* close the data and the key files */ close(kpt); close(dpt); /* sort the key file if updates were made */ if(ovrflw!=0) ksort(file); /* update the dcb file */ recs=recs+ovrflw; dcbrec.nrecs=recs; dcbrec.dadd=daddr; dcbrec.openflag=BLANK; /* open the dcb file */ strcpy(fname,file); strcat(fname,ddcb); dp=open(fname,2); write(dp, &dcbrec, sizeof (struct dcbrec) ); close(dp); return(SUCCESS); } /* this routine puts the data file pointer in the key record */ kputpt(buffer,lng,start) char buffer[]; long lng; int start; { int i=8, j; long l; char temp[9]; l=lng; if(l==0L) temp[i--]=ZERO; while(l){ temp[i--] = l % 10 + ZERO; l = l / 10;} while(i>=0) temp[i--]=BLANK; for(i=0, j=start;i<9;i++,j++) buffer[j]=temp[i]; keyrec[keyl+10]=NEWLINE; return; } /* this routine sorts the key file in ascending key order */ ksort(file) char file[]; { char fname[14]; int i; strcpy(fname,file); strcat(fname,dkey); i=fork(); if(i==0) execl(SORT,SORT,"-o",fname,fname,0); while(wait()!=i); return(SUCCESS); } /* this routine reconstructs the data and key files used by keyio */ /* it removes deleted records and assembles the data and key files */ kfresh(file) char file[]; { int i,krecl,klen,kp,dp,tk,td; char fname[17],fname1[17],keyrec[41],datrec[16500]; /* try to open the data file */ i=kopen(file); if( (i>0 & i<5) || i==13) return(i); /* get index */ recs=0L; daddr=0L; /* set up variables */ klen=keyl; krecl=klen+11; kp=kpt; dp=dpt; /* create the temporary work files */ creat(tmpd,0644); creat(tmpk,0644); /* open the temporary files */ tk=open(tmpk,2); td=open(tmpd,2); /* read each record from the key file */ while((i=read(kp,keyrec,krecl))!=0){ if(i==(-1)) return(RDERR); /* only process non deleted records */ if(keyrec[klen]!=ONE){ /* get pointer of data record */ kgetpt(keyrec); /* get data record and rewrite key and data records */ kget(dp,pointer,datrec,lrecl); kputpt(keyrec,daddr,(klen+1)); kput(tk,0L,keyrec,krecl,2); kput(td,0L,datrec,lrecl,2); recs++; daddr+=lrecl; } } /* close the files which are being refreshed */ close(dp); close(kp); close(td); close(tk); /* if we do not have the keep option then */ /* remove the data file and the key file. after this copy the temp */ /* files over to the old names and destroy temp files */ if(kflag) { strcpy(fname,file); strcat(fname,bak); kfcpy(file,fname); strcpy(fname,file); strcat(fname,dkey); strcat(fname,bak); strcpy(fname1,file); strcat(fname1,dkey); kfcpy(fname1,fname); strcpy(fname1,file); strcat(fname1,ddcb); strcpy(fname,file); strcat(fname,ddcb); strcat(fname,bak); i=fork(); if(i==0) { execl(CP,CP,fname1,fname,0); exit(0);} while(i!=wait());} kfcpy(tmpd,file); strcpy(fname,file); strcat(fname,dkey); kfcpy(tmpk,fname); recs--; ovrflw=1; kclose(file); } /* this routine copies one file to another and deletes the first file */ kfcpy(file1,file2) char *file1,*file2; { int pid; pid=fork(); if(pid==0){ execl(MV,MV,file1,file2,0); exit(-1);} while(pid!=wait()); } qBA5j 4/ecm2/setuphG  &6  w # (@ z5@ z 5f@& %5N  wDw 4%t@ w % f  5%f h Nfe  (fe  fe h Nfe  -fe  fe h 5wtwl rb ^2 %f %N X w < B 5  ʥ ʥ ʥ- ʥ9 Wp @@`eʥ0  w ww wDe~   % w7 7 ׯ-   Hw7  . 6wXB J7f    ӕ-    ӕ- f&E ? r@A r  f  e0 9e   ҋ D~  x&  mz x ~    ~ _7 L B >0   *Wp `e0eӕ?w DCӋ @ww DC@wf ,P   @f  7j -|t wp0,wXw:w@& BFF7command is: 'setup file' ** setup complete ** -- setup err#%d -- .key.dcbKey length = %d Record length = %d vdls\ocDL`OhxlXf$eTruUqA,5j4/ecm2/setup.cc/* * This routine is used to set up a keyed file for use with the * the keyio i/o routines * * Written by Steve Saper * AECOM 1979 */ #include "keyio.h" #define FILEMODE 0644 main(num,arg) int num; char *arg[]; { int i,keyl,lrecl; if(num<4) printf("command is: 'setup file'\n"); else { keyl = atoi(arg[2]); lrecl=atoi(arg[3])+1; i=ksetup(arg[1],keyl,lrecl); if(i==0) printf("** setup complete **\n"); else printf("-- setup err#%d --\n",i); } } ksetup(file,keyl,lrecl) char *file; int keyl,lrecl; { int fp,j; char name1[FDKLEN]; if (lrecl>MAXREC) return(BADLREC); if (keyl>MAXKEY) return(BADKEYL); if( (fp=open(file,0)) !=-1 ) return(FILTHR); else { /* creat the data and key files */ creat(file,FILEMODE); strcpy(name1,file); strcat(name1,".key"); creat(name1,FILEMODE); /* create the dcb file */ strcpy(name1,file); strcat(name1,".dcb"); fp=creat(name1,FILEMODE); dcbrec.keyl = keyl; dcbrec.lrecl = lrecl; dcbrec.openflag = ' '; printf("Key length = %d Record length = %d\n", dcbrec.keyl, dcbrec.lrecl-1); write(fp,&dcbrec, sizeof (struct dcbrec)); close(fp); return(SUCCESS); } } q@85j4/ecm2/system_notes The code for keyio was written to run on a PDP 11/70 computer running under PWB UNIX. There should be little problem transferring keyio to another version of UNIX except for the following. Keyio uses the system call "lseek" which is exactly the same in function as "seek" except that the file offset is a long integer instead of a 2 byte integer. If "lseek" or its equivalent is not available under your UNIX version it will have to be simulated through a user written routine using "seek". Keyio uses the standard UNIX utility programs "cp", "mv", and "sort". These programs are expected to reside in the directory "/bin". On our computer the keyio utilities setup, refresh, and kchk reside in the directory "/local/bin". The test program "note" which is included with keyio expects these routines to reside in this directory. If you install these routines in another directory, the program will have to be recompiled. qA"i\ 4/n.y.bloodqAQi\4/n.y.blood/manq4i4/n.y.blood/man/concat.3 .TH CONCAT III .SH NAME concat \- concatenate a series of strings into one. .SH SYNOPSIS .B concat(dest, str1, str2, ..., 0) .br .B char *dest, *str1, *str2, ... .SH DESCRIPTION .I concat concatenates a series of character strings into .I dest. No checking for overflow is done on .I dest so it is the programmers responsibility to provide a large enough buffer. .SH AUTHOR njm q@i4/n.y.blood/man/convert.1.TH CONVERT 1 .SH NAME convert \- prepare v6 file to run on v7 .SH SYNOPSIS .B convert files... .SH DESCRIPTION .I convert allows a v6 executable program to run under v7 by changing the header on the v6 program to one that the systems knows is to be treated specially with v6 system calls. (stty not included). Care should be taken, however when depending on header contents in other situations (ie. adb file etc) .SH "SEE ALSO" /usr/sys/sys/sys1.c .SH BUGS to be discovered. qCi:4/n.y.blood/man/equ.3 .TH EQU III .SH NAME equ \- test equality of strings. .SH SYNOPSIS .B equ(str1, str2) .br .B char *str1, *str2; .SH DESCRIPTION .I equ simply returns a nonzero value if the two strings are equal; A zero otherwise. Note that one string cannot be a prefix of the other, they have to match exactly. .SH AUTHOR njm qOin 4/n.y.blood/man/news.1. .TH NEWS I .SH NAME news \- post or review system news. .SH SYNOPSIS .B News [ .B \-i ][ .B \-f file ][ .B \-g grp,... ][ .B \-p file ][ .B \-n name ][ .B \-a ] .SH DESCRIPTION .I News is a utility for posting and reviewing system news or news items specific to any established (/etc/group) or unestablished group of users. It is similar to mail(I) in function, the main difference being that there is only one file for all users compared with the one file per user mail deals with (thus space and redundancy is reduced. .LP With no arguments news prints out each news item (first in-first out) together with its installation date, not yet seen by the user or not yet deleted from their news queue. .LP The following is a list of flag options: .TP .B \-a Normally only items of concern are printed (those items having your uid set in the file header). This option, however, displays all options regardless of header settings. .TP .B \-i This puts news in input mode reading the standard input as the news file. Input is ended with contrl-D. This mode is limited to those users listed in the news group (/etc/group). .TP .B \-f Input for the item is taken from the file following this flag instead of the standard input. .TP .B \-g .I News items manifest normally to all users not containing a '-' in the fifth field of their passwd entry. This option restricts manifestation to all members of the comma separated list of established groups (those listed in /etc/group). .TP .B \-p This further restricts the news to the users listed (one per line) in the file following this flag so that any combination of users may recieve the news. .TP .B \-n Normally the news file resides in /usr/news with a process number as its root name. This option forces the root name to be the word following this flag. This is useful to help identify the news files in the /usr/news directory. .LP Any combination of -f, -g, -p, and -n automatically implies -i which can, therefore, be ommited. .LP If niether -g or -p is used then all users (except those whose passwd entry contains a '-' in the fifth field) will receive the news; Otherwise it is directed to only those represented by either flag receive the news. .LP For each item printed out a single letter command is read from the terminal to detirmine the disposition of the message. The commands are identical to those in mail(I) with the omission of w, m, x, and !. Note that in response to the command "s" the news item is saved in a file called "nbox". This file can be perused a any time with "mail -f nbox". .LP .I News will repeatedly show the same items each time unless the user deletes it from his queue or saves it in his nbox. .LP Users authorized to post news must execute "newgrp news" before invoking news. It is also advisable to change back to the original group when finished. .SH FILES /usr/news/* news files .br /etc/group established groups .br /etc/passwd used to select users .SH SEE ALSO passwd(V), mail(I), newgrp(I), group(I) .SH BUGS There is a locking mechanism to prevent file overwriting but it is not perfect and races are possible. Login should notify the user of news to be examined. .SH AUTHOR njm qA1i\4/n.y.blood/srcq>i4/n.y.blood/src/concat.c/* concatenate a series of strings into "dest". * list is terminated by NULL pointer. */ concat(dest, strs) char *dest, *strs; { char **scrv, *p, *q; scrv = &strs; for(q = dest; p = *scrv; scrv++) while(*p) *q++ = *p++; *q = '\0'; return(dest); } qMi24/n.y.blood/src/convert.c/* This program converts the header on executable files to one * that is recognized by the nybc v7 system as being a version 6 * executable file. The system code for handling this is in * getxfile (sys1.c). * njm - 10/31/79 */ #define V6 0100 main(argc, argv) int argc; char **argv; { int mag, fd; for( ; argc > 1; argc--, argv++) { printf("%s: ", argv[1]); if((fd = open(argv[1], 2)) < 0) { perror("Open err."); continue; } if(read(fd, &mag, 2) != 2) { perror("Read err."); continue; } if((mag == 0407) || (mag == 0410) || (mag == 0411) || (mag == 0405)) { mag |= V6; lseek(fd, (long)0, 0); if(write(fd, &mag, 2) != 2) { perror("Write err."); continue; } printf("Done.\n"); } else printf("Not Executable.\n"); close(fd); } } qJi4/n.y.blood/src/equ.c#define NO 0 #define YES 1 equ(st1, st2) char *st1, *st2; { while(*st1 == *st2) { if(!(*st1)) break; st1++; st2++; } return((*st1 || *st2) ? NO : YES); } q8i4/n.y.blood/src/news.c./* news program - posting and reviewing news items in directory '/usr/news' * posting is restricted to those users in news group after 'newgrp news' * is executed. Each news file has a bit map of uids as a header. * when a reader deletes a news item from his queue the corresponding bit * is turned off. when all are turned off the file is deleted. * author - naim mowatt */ #include #include #include #include #include #include #include #include #include #define NMESIZE 25 #define NNEWS 30 /* number of news files */ #define RDENT(fd) read(fd, &buf, 16) #define PUTDAT(dte, fd) write(fd, ctime(&dte), 25) char fnme[NMESIZE]; char iobuf[BUFSIZ]; char *nfle = 0; char *grps = 0; char *ifle = 0; char *pfle = 0; int locked = 0; int uid; int dirfd; /* file descriptor for news directory */ int aflg = 0; struct flstr /* structure for time sorting news files */ { long floff; /* offset in directory where fnme is located */ long date; /* installation date of news file */ struct flstr *forw; struct flstr *back; } nwsfls[NNEWS], *headst, *lastst; struct nhdr hdr; /* all newsfiles begin with this header */ main(argc, argv) int argc; char *argv[]; { int i, ifd, ofd, cleanup(); char *p, buf[BUFSIZ]; struct flstr *q; uid = getuid(); if (argc > 1) { for(i = 1; i < argc; i++) switch(argv[i][1]) { case 'a': /* look at all files ignore id seting */ aflg++; goto peruse; case 'n': /* name of installed news file */ nfle = argv[++i]; break; case 'g': /* news only for grps */ grps = argv[++i]; break; case 'f': /* input filename */ ifle = argv[++i]; break; case 'i': /* input mode */ break; case 'p': /* file of user names */ pfle = argv[++i]; break; default: fprintf(stderr, "Bad specifier: %s\n", argv[i]); exit(1); } if(chkusr() == 0) { fprintf(stderr, "Not authorized to post news\n"); exit(1); } if(pfle) mapusr(pfle); for(p = grps; p && *p; ) { while(*p && *p != ',') p++; if(*p == ',') *p++ = '\0'; if(grpmap(grps) < 0) { fprintf(stderr, "Unknown group: %s\n", grps); exit(1); } if(*p) grps = p; } if(grps == 0 && pfle == 0) fixmap(); time(&hdr.dte); if(ifle) { ifd = open(ifle, 0); if(ifd < 0) { fprintf(stderr, "Can't open input file.\n"); exit(1); } } else ifd = 0; if(nfle && access(concat(fnme, NWSDIR, nfle, ".nws", 0), 0) < 0) ofd = creat(fnme, 0666); else ofd = creat(concat(fnme,mktemp(NWSFLE), ".nws", 0), 0666); if(write(ofd, &hdr, sizeof(hdr)) != sizeof(hdr)) { fprintf(stderr, "Unable to write news file\n"); exit(1); } signal(SIGINT, cleanup); signal(SIGQUIT, cleanup); while((i = read(ifd, &iobuf, sizeof(buf))) > 0) write(ofd, &iobuf, i); } else peruse: { char resp[NMESIZE]; int print; if(tsortnws() == 0) { fprintf(stderr, "No news.\n"); exit(0); } print = 1; dirfd = open(NWSDIR, 0); for(q = nwsfls; q; ) { if(print) printnws(q, 1); print = 1; printf("?"); if(fgets(resp, NMESIZE, stdin) == NULL || resp[0] == 'q') break; switch(resp[0]) { case 'p': continue; case '-': case '^': if((q = q->back) == 0) q = headst; break; case 's': if(resp[1] != '\n' && resp[1] != '\0') { for(i = 1; isspace(resp[i]); i++) ; nfle = &resp[i]; } else nfle = "nbox"; if((ofd = open(nfle, 1)) > 0) lseek(ofd, 0L, 2); else if((ofd = creat(nfle, 0666)) > 0) ; else { fprintf(stderr, "Can't open %s\n", nfle); print = 0; continue; } printnws(q, ofd); close(ofd); case 'd': USETID(uid); copyback(q); case '+': case 'n': case '\n': q = q->forw; break; case '?': case 'h': default: fprintf(stderr, "n\tnext\n"); fprintf(stderr, "p\tprint again\n"); fprintf(stderr, "-\tprint previous\n"); fprintf(stderr, "s[file]\tappend to file (news default)\n"); fprintf(stderr, "d\tdelete message\n"); print = 0; } } } } allread() { int i; for(i = 0; i < NIDS; i++) if(hdr.ids[i]) return(0); return(1); } chkusr() { char *p; struct passwd *pd; struct group *gp; pd = getpwuid(uid); gp = getgrnam("news"); endpwent(); for( ; p = *gp->gr_mem; gp->gr_mem++) if(equ(p, pd->pw_name)) { endgrent(); return(1); } endgrent(); return(0); } cleanup() { unlink(fnme); exit(1); } copyback(q) struct flstr *q; { int qfd, n; char fnm[BUFSIZ], entry[16]; lseek(dirfd, q->floff, 0); read(dirfd, &entry, 16); concat(fnm, NWSDIR, entry, 0); if(allread()) { unlink(&fnm); n = 0; } else n = 1; qfd = open(fnm, 1); lock(fnm); if(write(qfd, &hdr, sizeof(hdr)) != sizeof(hdr)) n = -1; unlock(fnm); close(qfd); return(n); } dsort(nsp) struct flst *nsp; { struct flst *q; for(q = headst; q ; q = q->forw) if(q->date > nsp->date) break; if(headst == 0) { lastst = headst = nsp; } else if(q == headst) { nsp->forw = q; headst = nsp; } else if(q == 0) { nsp->back = lastst; lastst->forw = nsp; lastst = nsp; } else { nsp->forw = q; nsp->back = q->back; q->back->forw = nsp; q->back = nsp; } } /* set uids of all users who do not have - in gecos field */ fixmap() { struct passwd *ps; while(ps = getpwent()) if(*ps->pw_gecos != '-') SETID(ps->pw_uid); endpwent(); } grpmap(grp) char *grp; { struct group *gp; struct passwd *pd; char *p; if((gp = getgrnam(grp)) == NULL) return(-1); for( ; p = *gp->gr_mem; gp->gr_mem++) { pd = getpwnam(p); if(pd == NULL) continue; if(*pd->pw_gecos != '-') SETID(pd->pw_uid); } setpwent(); while(pd = getpwent()) if((pd->pw_gid == gp->gr_gid) && (*pd->pw_gecos != '-')) SETID(pd->pw_uid); endpwent(); return(1); } lock(fle) char *fle; { struct stat stbuf; if(stat(fle, &stbuf) < 0) return; while(stbuf.st_mode & 01) { sleep(30); stat(fle, &stbuf); } chmod(fle, stbuf.st_mode | 01); locked = stbuf.st_mode | 01; /* news files have to be owned by owner of "news" */ /* setuid bit */ } mapusr(ufle) char *ufle; { FILE *strm; char nbuf[NMESIZE]; struct passwd *pd; strm = fopen(ufle, "r"); if(strm == NULL) { fprintf(stderr, "Cannot open %s.\n", ufle); exit(1); } while(fgets(nbuf, NMESIZE, strm)) { pd = getpwnam(zapnl(nbuf)); if(pd == NULL) continue; SETID(pd->pw_uid); } } printnws(flst, outfd) struct flstr * flst; int outfd; { int flsfd, n; char entry[16], fnm[BUFSIZ]; lseek(dirfd, flst->floff, 0); /* dirfd = fle descrip. for /usr/news */ read(dirfd, &entry, 16); flsfd = open(concat(fnm, NWSDIR, &entry, 0), 0); write(outfd, "From News ", 10); lock(&fnm); read(flsfd, &hdr, sizeof(hdr)); PUTDAT(hdr.dte, outfd); while((n = read(flsfd, &iobuf, sizeof(iobuf))) > 0) write(outfd, &iobuf, n); write(outfd, "\n", 1); unlock(&fnm); close (flsfd); } /* sort all news files in /usr/news according to time installed */ tsortnws() { struct nwsfls *nsp; char buf[BUFSIZ], fnm[BUFSIZ]; int diroff, nwdfd, nwffd, i, n; struct direct *dirp; nwdfd = open(NWSDIR, 0); lseek(nwdfd, 32L, 0); diroff = 34; /* "" */ dirp = &buf; i = 0; for(n = RDENT(nwdfd); n == 16; n = RDENT(nwdfd), diroff += 16) { if(dirp->d_ino == 0) continue; nwffd = open(concat(fnm, NWSDIR, dirp->d_name, 0), 0); if((read(nwffd, &hdr, sizeof(hdr)) < sizeof(hdr)) || (!ISSET(uid) && aflg == 0)) { close(nwffd); continue; } nsp = &nwsfls[i++]; nsp->floff = diroff; nsp->date = hdr.dte; dsort(nsp); close(nwffd); } close(nwdfd); return(i); } unlock(fle) char *fle; { if(locked) { chmod(fle, locked & ~01); locked = 0; } } zapnl(buf) char buf[]; { register char *p; for(p = buf; *p; p++) if(*p == '\n') { *p = '\0'; break; } return(buf); } qARi\4/n.y.blood/v6-7eqi4/n.y.blood/v6-7/READ.METhe files in this directory are needed to run v6 executables under v7. they should replace the regular v7 files of the same name and the system should be remade using these. sysent contains the old tell system call. You may want to change the placement within the sysent table. user.h contains the definitions for the V6 test and the V6 bit used by the differing system calls. sys1 has the change to recognize a v6 program. sys2.c has the changed system calls. convert is the utility to convert an object file to be a v6 executable. rqyi(4/n.y.blood/v6-7/stat.hstruct stat { dev_t st_dev; ino_t st_ino; unsigned short st_mode; short st_nlink; short st_uid; short st_gid; dev_t st_rdev; off_t st_size; time_t st_atime; time_t st_mtime; time_t st_ctime; }; /* To support the v6 stat call * njm - 10/20/79 */ struct stat6 { dev_t st6_dev; ino_t st6_ino; unsigned int st6_mode; char st6_nlink; char st6_uid; char st6_gid; char st6_sze0; int st6_sze1; int st6_addr[8]; long st6_atime; long st6_mtime; }; #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_IFMPC 0030000 /* multiplexed char special */ #define S_IFMPB 0070000 /* multiplexed block special */ #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 */ eq_i&4/n.y.blood/v6-7/sys1.c#include "../h/param.h" #include "../h/systm.h" #include "../h/map.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/proc.h" #include "../h/buf.h" #include "../h/reg.h" #include "../h/inode.h" #include "../h/seg.h" #include "../h/acct.h" /* * exec system call, with and without environments. */ struct execa { char *fname; char **argp; char **envp; }; exec() { ((struct execa *)u.u_ap)->envp = NULL; exece(); } exece() { register nc; register char *cp; register struct buf *bp; register struct execa *uap; int na, ne, bno, ucp, ap, c; struct inode *ip; if ((ip = namei(uchar, 0)) == NULL) return; bno = 0; bp = 0; if(access(ip, IEXEC)) goto bad; if((ip->i_mode & IFMT) != IFREG || (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) { u.u_error = EACCES; goto bad; } /* * Collect arguments on "file" in swap space. */ na = 0; ne = 0; nc = 0; uap = (struct execa *)u.u_ap; if ((bno = malloc(swapmap,(NCARGS+BSIZE-1)/BSIZE)) == 0) panic("Out of swap"); if (uap->argp) for (;;) { ap = NULL; if (uap->argp) { ap = fuword((caddr_t)uap->argp); uap->argp++; } if (ap==NULL && uap->envp) { uap->argp = NULL; if ((ap = fuword((caddr_t)uap->envp)) == NULL) break; uap->envp++; ne++; } if (ap==NULL) break; na++; if(ap == -1) u.u_error = EFAULT; do { if (nc >= NCARGS-1) u.u_error = E2BIG; if ((c = fubyte((caddr_t)ap++)) < 0) u.u_error = EFAULT; if (u.u_error) goto bad; if ((nc&BMASK) == 0) { if (bp) bawrite(bp); bp = getblk(swapdev, swplo+bno+(nc>>BSHIFT)); cp = bp->b_un.b_addr; } nc++; *cp++ = c; } while (c>0); } if (bp) bawrite(bp); bp = 0; nc = (nc + NBPW-1) & ~(NBPW-1); if (getxfile(ip, nc) || u.u_error) goto bad; /* * copy back arglist */ ucp = -nc - NBPW; ap = ucp - na*NBPW - 3*NBPW; u.u_ar0[R6] = ap; suword((caddr_t)ap, na-ne); nc = 0; for (;;) { ap += NBPW; if (na==ne) { suword((caddr_t)ap, 0); ap += NBPW; } if (--na < 0) break; suword((caddr_t)ap, ucp); do { if ((nc&BMASK) == 0) { if (bp) brelse(bp); bp = bread(swapdev, swplo+bno+(nc>>BSHIFT)); cp = bp->b_un.b_addr; } subyte((caddr_t)ucp++, (c = *cp++)); nc++; } while(c&0377); } suword((caddr_t)ap, 0); suword((caddr_t)ucp, 0); setregs(); bad: if (bp) brelse(bp); if(bno) mfree(swapmap, (NCARGS+BSIZE-1)/BSIZE, bno); iput(ip); } /* * Read in and set up memory for executed file. * Zero return is normal; * non-zero means only the text is being replaced */ getxfile(ip, nargc) register struct inode *ip; { register unsigned ds; register sep; register unsigned ts, ss; register i, overlay; long lsize; /* * read in first few bytes * of file for segment * sizes: * ux_mag = 407/410/411/405 * 407 is plain executable * 410 is RO text * 411 is separated ID * 405 is overlaid text */ u.u_base = (caddr_t)&u.u_exdata; u.u_count = sizeof(u.u_exdata); u.u_offset = 0; u.u_segflg = 1; readi(ip); u.u_segflg = 0; if(u.u_error) goto bad; if (u.u_count!=0) { u.u_error = ENOEXEC; goto bad; } sep = 0; overlay = 0;  if((u.u_exdata.ux_mag & ~V6) == 0407) { lsize = (long)u.u_exdata.ux_dsize + u.u_exdata.ux_tsize; u.u_exdata.ux_dsize = lsize; if (lsize != u.u_exdata.ux_dsize) { /* check overflow */ u.u_error = ENOMEM; goto bad; } u.u_exdata.ux_tsize = 0; } else if ((u.u_exdata.ux_mag & ~V6) == 0411) sep++; else if ((u.u_exdata.ux_mag & ~V6) == 0405) overlay++; else if ((u.u_exdata.ux_mag & ~V6) != 0410) { u.u_error = ENOEXEC; goto bad; } if(u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && ip->i_count!=1) { u.u_error = ETXTBSY; goto bad; } /* * find text and data sizes * try them out for possible * overflow of max sizes */ ts = btoc(u.u_exdata.ux_tsize); lsize = (long)u.u_exdata.ux_dsize + u.u_exdata.ux_bsize; if (lsize != (unsigned)lsize) { u.u_error = ENOMEM; goto bad; } ds = btoc(lsize); ss = SSIZE + btoc(nargc); if (overlay) { if (u.u_sep==0 && ctos(ts) != ctos(u.u_tsize) || nargc) { u.u_error = ENOMEM; goto bad; } ds = u.u_dsize; ss = u.u_ssize; sep = u.u_sep; xfree(); xalloc(ip); u.u_ar0[PC] = u.u_exdata.ux_entloc & ~01; } else { if(estabur(ts, ds, ss, sep, RO)) goto bad; /* * allocate and clear core * at this point, committed * to the new image */ if(u.u_exdata.ux_mag & V6) u.u_fpflag |= V6; else u.u_fpflag &= ~V6; u.u_prof.pr_scale = 0; xfree(); i = USIZE+ds+ss; expand(i); while(--i >= USIZE) clearseg(u.u_procp->p_addr+i); xalloc(ip); /* * read in data segment */ estabur((unsigned)0, ds, (unsigned)0, 0, RO); u.u_base = 0; u.u_offset = sizeof(u.u_exdata)+u.u_exdata.ux_tsize; u.u_count = u.u_exdata.ux_dsize; readi(ip); /* * set SUID/SGID protections, if no tracing */ if ((u.u_procp->p_flag&STRC)==0) { if(ip->i_mode&ISUID) if(u.u_uid != 0) { u.u_uid = ip->i_uid; u.u_procp->p_uid = ip->i_uid; } if(ip->i_mode&ISGID) u.u_gid = ip->i_gid; } else psignal(u.u_procp, SIGTRC); } u.u_tsize = ts; u.u_dsize = ds; u.u_ssize = ss; u.u_sep = sep; estabur(ts, ds, ss, sep, RO); bad: return(overlay); } /* * Clear registers on exec */ setregs() { register int *rp; register char *cp; register i; for(rp = &u.u_signal[0]; rp < &u.u_signal[NSIG]; rp++) if((*rp & 1) == 0) *rp = 0; for(cp = ®loc[0]; cp < ®loc[6];) u.u_ar0[*cp++] = 0; u.u_ar0[PC] = u.u_exdata.ux_entloc & ~01; for(rp = (int *)&u.u_fps; rp < (int *)&u.u_fps.u_fpregs[6];) *rp++ = 0; for(i=0; irval & 0377) << 8); } /* * Release resources. * Save u. area for parent to look at. * Enter zombie state. * Wake up parent and init processes, * and dispose of children. */ exit(rv) { register int i; register struct proc *p, *q; register struct file *f; p = u.u_procp; p->p_flag &= ~(STRC|SULOCK); p->p_clktim = 0; for(i=0; ip_size, p->p_addr); p->p_stat = SZOMB; ((struct xproc *)p)->xp_xstat = rv; ((struct xproc *)p)->xp_utime = u.u_cutime + u.u_utime; ((struct xproc *)p)->xp_stime = u.u_cstime + u.u_stime; for(q = &proc[0]; q < &proc[NPROC]; q++) if(q->p_ppid == p->p_pid) { wakeup((caddr_t)&proc[1]); q->p_ppid = 1; if (q->p_stat==SSTOP) setrun(q); } for(q = &proc[0]; q < &proc[NPROC]; q++) if(p->p_ppid == q->p_pid) { wakeup((caddr_t)q); swtch(); /* no return */ } swtch(); } /* * Wait system call. * Search for a terminated (zombie) child, * finally lay it to rest, and collect its status. * Look also for stopped (traced) children, * and pass back status from them. */ wait() { register f; register struct proc *p; f = 0; loop: for(p = &proc[0]; p < &proc[NPROC]; p++) if(p->p_ppid == u.u_procp->p_pid) { f++; if(p->p_stat == SZOMB) { u.u_r.r_val1 = p->p_pid; u.u_r.r_val2 = ((struct xproc *)p)->xp_xstat; u.u_cutime += ((struct xproc *)p)->xp_utime; u.u_cstime += ((struct xproc *)p)->xp_stime; p->p_pid = 0; p->p_ppid = 0; p->p_pgrp = 0; p->p_sig = 0; p->p_flag = 0; p->p_wchan = 0; p->p_stat = NULL; return; } if(p->p_stat == SSTOP) { if((p->p_flag&SWTED) == 0) { p->p_flag |= SWTED; u.u_r.r_val1 = p->p_pid; u.u_r.r_val2 = (fsig(p)<<8) | 0177; return; } continue; } } if(f) { sleep((caddr_t)u.u_procp, PWAIT); goto loop; } u.u_error = ECHILD; } /* * fork system call. */ fork() { register struct proc *p1, *p2; register a; /* * Make sure there's enough swap space for max * core image, thus reducing chances of running out */ if ((a = malloc(swapmap, ctod(MAXMEM))) == 0) { u.u_error = ENOMEM; goto out; } mfree(swapmap, ctod(MAXMEM), a); a = 0; p2 = NULL; for(p1 = &proc[0]; p1 < &proc[NPROC]; p1++) { if (p1->p_stat==NULL && p2==NULL) p2 = p1; else { if (p1->p_uid==u.u_uid && p1->p_stat!=NULL) a++; } } /* * Disallow if * No processes at all; * not su and too many procs owned; or * not su and would take last slot. */ if (p2==NULL || (u.u_uid!=0 && (p2==&proc[NPROC-1] || a>MAXUPRC))) { u.u_error = EAGAIN; goto out; } p1 = u.u_procp; if(newproc()) { u.u_r.r_val1 = p1->p_pid; u.u_start = time; u.u_cstime = 0; u.u_stime = 0; u.u_cutime = 0; u.u_utime = 0; u.u_acflag = AFORK; return; } u.u_r.r_val1 = p2->p_pid; out: u.u_ar0[R7] += NBPW; } /* * break system call. * -- bad planning: "break" is a dirty word in C. */ sbreak() { struct a { char *nsiz; }; register a, n, d; int i; /* * set n to new data size * set d to new-old * set n to new total size */ n = btoc((int)((struct a *)u.u_ap)->nsiz); if(!u.u_sep) n -= ctos(u.u_tsize) * stoc(1); if(n < 0) n = 0; d = n - u.u_dsize; n += USIZE+u.u_ssize; if(estabur(u.u_tsize, u.u_dsize+d, u.u_ssize, u.u_sep, RO)) return; u.u_dsize += d; if(d > 0) goto bigger; a = u.u_procp->p_addr + n - u.u_ssize; i = n; n = u.u_ssize; while(n--) { copyseg(a-d, a); a++; } expand(i); return; bigger: expand(n); a = u.u_procp->p_addr + n; n = u.u_ssize; while(n--) { a--; copyseg(a-d, a); } while(d--) clearseg(--a); } qri4/n.y.blood/v6-7/sys2.c#include "../h/param.h" #include "../h/systm.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/reg.h" #include "../h/file.h" #include "../h/inode.h" /* * read system call */ read() { rdwr(FREAD); } /* * write system call */ write() { rdwr(FWRITE); } /* * common code for read and write calls: * check permissions, set base, count, and offset, * and switch out to readi, writei, or pipe code. */ rdwr(mode) register mode; { register struct file *fp; register struct inode *ip; register struct a { int fdes; char *cbuf; unsigned count; } *uap; uap = (struct a *)u.u_ap; fp = getf(uap->fdes); if(fp == NULL) return; if((fp->f_flag&mode) == 0) { u.u_error = EBADF; return; } u.u_base = (caddr_t)uap->cbuf; u.u_count = uap->count; u.u_segflg = 0; if((fp->f_flag&FPIPE) != 0) { if(mode == FREAD) readp(fp); else writep(fp); } else { ip = fp->f_inode; if (fp->f_flag&FMP) u.u_offset = 0; else u.u_offset = fp->f_un.f_offset; if((ip->i_mode&(IFCHR&IFBLK)) == 0) plock(ip); if(mode == FREAD) readi(ip); else writei(ip); if((ip->i_mode&(IFCHR&IFBLK)) == 0) prele(ip); if ((fp->f_flag&FMP) == 0) fp->f_un.f_offset += uap->count-u.u_count; } u.u_r.r_val1 = uap->count-u.u_count; } /* * open system call */ open() { register struct inode *ip; register struct a { char *fname; int rwmode; } *uap; uap = (struct a *)u.u_ap; ip = namei(uchar, 0); if(ip == NULL) return; open1(ip, ++uap->rwmode, 0); } /* * creat system call */ creat() { register struct inode *ip; register struct a { char *fname; int fmode; } *uap; uap = (struct a *)u.u_ap; ip = namei(uchar, 1); if(ip == NULL) { if(u.u_error) return; ip = maknode(uap->fmode&07777&(~ISVTX)); if (ip==NULL) return; open1(ip, FWRITE, 2); } else open1(ip, FWRITE, 1); } /* * common code for open and creat. * Check permissions, allocate an open file structure, * and call the device open routine if any. */ open1(ip, mode, trf) register struct inode *ip; register mode; { register struct file *fp; int i; if(trf != 2) { if(mode&FREAD) access(ip, IREAD); if(mode&FWRITE) { access(ip, IWRITE); if((ip->i_mode&IFMT) == IFDIR) u.u_error = EISDIR; } } if(u.u_error) goto out; if(trf == 1) itrunc(ip); prele(ip); if ((fp = falloc()) == NULL) goto out; fp->f_flag = mode&(FREAD|FWRITE); fp->f_inode = ip; i = u.u_r.r_val1; openi(ip, mode&FWRITE); if(u.u_error == 0) return; u.u_ofile[i] = NULL; fp->f_count--; out: iput(ip); } /* * close system call */ close() { register struct file *fp; register struct a { int fdes; } *uap; uap = (struct a *)u.u_ap; fp = getf(uap->fdes); if(fp == NULL) return; u.u_ofile[uap->fdes] = NULL; closef(fp); } /* * seek system call * Changed to support the v6 seek call. * njm - 10/19/79 */ seek() { register struct file *fp; union { struct a { int fdes; off_t off; int sbase; }; struct a6 { int fdes; int off6; int sbs6; }; } *uap; off_t pos; uap = u.u_ap; fp =getf(uap->fdes); if(fp == NULL) return; if(fp->f_flag&(FPIPE | FMP)) { u.u_error = ESPIPE; return; } if(ISV6) { pos = uap->off6; if(uap->sbs6 > 2) { pos <<= 9; uap->sbs6 -= 3; } if(uap->sbs6 == 1) pos += fp->f_un.f_offset; else if(uap->sbs6 == 2) pos += fp->f_inode->i_size; fp->f_un.f_offset = pos; return; } if(uap->sbase == 1) uap->off += fp->f_un.f_offset; else if(uap->sbase == 2) uap->off += fp->f_inode->i_size; fp->f_un.f_offset = uap->off; u.u_r.r_off = uap->off; } /* * link system call */ link() { register struct inode *ip, *xp; register struct a { char *target; char *linkname; } *uap; uap = (struct a *)u.u_ap; ip = namei(uchar, 0); if(ip == NULL) return; if((ip->i_mode&IFMT)==IFDIR && !suser()) goto out; /* * Unlock to avoid possibly hanging the namei. * Sadly, this means races. (Suppose someone * deletes the file in the meantime?) * Nor can it be locked again later * because then there will be deadly * embraces. */ prele(ip); u.u_dirp = (caddr_t)uap->linkname; xp = namei(uchar, 1); if(xp != NULL) { u.u_error = EEXIST; iput(xp); goto out; } if (u.u_error) goto out; if(u.u_pdir->i_dev != ip->i_dev) { iput(u.u_pdir); u.u_error = EXDEV; goto out; } wdir(ip); if (u.u_error==0) { ip->i_nlink++; ip->i_flag |= ICHG; } out: iput(ip); } /* * mknod system call */ mknod() { register struct inode *ip; register struct a { char *fname; int fmode; int dev; } *uap; uap = (struct a *)u.u_ap; if(suser()) { ip = namei(uchar, 1); if(ip != NULL) { u.u_error = EEXIST; goto out; } } if(u.u_error) return; ip = maknode(uap->fmode); if (ip == NULL) return; ip->i_un.i_rdev = (dev_t)uap->dev; out: iput(ip); } /* * access system call */ saccess() { register svuid, svgid; register struct inode *ip; register struct a { char *fname; int fmode; } *uap; uap = (struct a *)u.u_ap; svuid = u.u_uid; svgid = u.u_gid; u.u_uid = u.u_ruid; u.u_gid = u.u_rgid; ip = namei(uchar, 0); if (ip != NULL) { if (uap->fmode&(IREAD>>6)) access(ip, IREAD); if (uap->fmode&(IWRITE>>6)) access(ip, IWRITE); if (uap->fmode&(IEXEC>>6)) access(ip, IEXEC); iput(ip); } u.u_uid = svuid; u.u_gid = svgid; } qi(4/n.y.blood/v6-7/sys3.c #include "../h/param.h" #include "../h/systm.h" #include "../h/mount.h" #include "../h/ino.h" #include "../h/reg.h" #include "../h/buf.h" #include "../h/filsys.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/inode.h" #include "../h/file.h" #include "../h/conf.h" #include "../h/stat.h" /* * the fstat system call. */ fstat() { register struct file *fp; register struct a { int fdes; struct stat *sb; } *uap; uap = (struct a *)u.u_ap; fp = getf(uap->fdes); if(fp == NULL) return; stat1(fp->f_inode, uap->sb, fp->f_flag&FPIPE? fp->f_un.f_offset: 0); } /* * the stat system call. */ stat() { register struct inode *ip; register struct a { char *fname; struct stat *sb; } *uap; uap = (struct a *)u.u_ap; ip = namei(uchar, 0); if(ip == NULL) return; stat1(ip, uap->sb, (off_t)0); iput(ip); } /* * The basic routine for fstat and stat: * get the inode and pass appropriate parts back. */ stat1(ip, ub, pipeadj) register struct inode *ip; struct stat *ub; off_t pipeadj; { register struct dinode *dp; register struct buf *bp; struct stat ds; struct stat6 ds6; int i, *p; iupdat(ip, &time, &time); bp = bread(ip->i_dev, itod(ip->i_number)); dp = bp->b_un.b_dino; dp += itoo(ip->i_number); if(ISV6) /* To support v6 stat calls */ /* Does not work on pipes */ /* njm - 10/19/79 */ { ds6.st6_dev = ip->i_dev; ds6.st6_ino = ip->i_number; ds6.st6_mode = ip->i_mode; ds6.st6_nlinks = ip->i_nlink; ds6.st6_uid = ip->i_uid; ds6.st6_gid = ip->i_gid; p = (int *) &ip->i_size; ds6.st6_sze0 = *p++; ds6.st6_sze1 = *p; for(i = 0; i < 8; i++) ds6.st6_addr[i] = 0; /* Watch out for this */ ds6.st6_atime = dp->di_atime; ds6.st6_mtime = dp->di_mtime; p = &ds6; } else { ds.st_dev = ip->i_dev; ds.st_ino = ip->i_number; ds.st_mode = ip->i_mode; ds.st_nlink = ip->i_nlink; ds.st_uid = ip->i_uid; ds.st_gid = ip->i_gid; ds.st_rdev = (dev_t)ip->i_un.i_rdev; ds.st_size = ip->i_size - pipeadj; ds.st_atime = dp->di_atime; ds.st_mtime = dp->di_mtime; p = &ds; } brelse(bp); if(copyout((caddr_t)p, (caddr_t)ub, (ISV6)? sizeof(ds6): sizeof(ds)) < 0) u.u_error = EFAULT; } /* * the dup system call. */ dup() { register struct file *fp; register struct a { int fdes; int fdes2; } *uap; register i, m; uap = (struct a *)u.u_ap; m = uap->fdes & ~077; uap->fdes &= 077; fp = getf(uap->fdes); if(fp == NULL) return; if ((m&0100) == 0) { if ((i = ufalloc()) < 0) return; } else { i = uap->fdes2; if (i<0 || i>=NOFILE) { u.u_error = EBADF; return; } u.u_r.r_val1 = i; } if (i!=uap->fdes) { if (u.u_ofile[i]!=NULL) closef(u.u_ofile[i]); u.u_ofile[i] = fp; fp->f_count++; } } /* * the mount system call. */ smount() { dev_t dev; register struct inode *ip; register struct mount *mp; struct mount *smp; register struct filsys *fp; struct buf *bp; register struct a { char *fspec; char *freg; int ronly; } *uap; uap = (struct a *)u.u_ap; dev = getmdev(); if(u.u_error) return; u.u_dirp = (caddr_t)uap->freg; ip = namei(uchar, 0); if(ip == NULL) return; if(ip->i_count!=1 || (ip->i_mode&(IFBLK&IFCHR))!=0) goto out; smp = NULL; for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { if(mp->m_bufp != NULL) { if(dev == mp->m_dev) goto out; } else if(smp == NULL) smp = mp; } mp = smp; if(mp == NULL) goto out; (*bdevsw[major(dev)].d_open)(dev, !uap->ronly); if(u.u_error) goto out; bp = bread(dev, SUPERB); if(u.u_error) { brelse(bp); goto out1; } mp->m_inodp = ip; mp->m_dev = dev; mp->m_bufp = geteblk(); bcopy((caddr_t)bp->b_un.b_addr, mp->m_bufp->b_un.b_addr, BSIZE); fp = mp->m_bufp->b_un.b_filsys; fp->s_ilock = 0; fp->s_flock = 0; fp->s_ronly = uap->ronly & 1; brelse(bp); ip->i_flag |= IMOUNT; prele(ip); return; out: u.u_error = EBUSY; out1: iput(ip); } /* * the umount system call. */ sumount() { dev_t dev; register struct inode *ip; register struct mount *mp; struct buf *bp; register struct a { char *fspec; }; dev = getmdev(); if(u.u_error) return; xumount(dev); /* remove unused sticky files from text table */ update(); for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) if(mp->m_bufp != NULL && dev == mp->m_dev) goto found; u.u_error = EINVAL; return; found: for(ip = &inode[0]; ip < &inode[NINODE]; ip++) if(ip->i_number != 0 && dev == ip->i_dev) { u.u_error = EBUSY; return; } (*bdevsw[major(dev)].d_close)(dev, 0); ip = mp->m_inodp; ip->i_flag &= ~IMOUNT; plock(ip); iput(ip); bp = mp->m_bufp; mp->m_bufp = NULL; brelse(bp); } /* * Common code for mount and umount. * Check that the user's argument is a reasonable * thing on which to mount, and return the device number if so. */ dev_t getmdev() { dev_t dev; register struct inode *ip; ip = namei(uchar, 0); if(ip == NULL) return(NODEV); if((ip->i_mode&IFMT) != IFBLK) u.u_error = ENOTBLK; dev = (dev_t)ip->i_un.i_rdev; if(major(dev) >= nblkdev) u.u_error = ENXIO; iput(ip); return(dev); } qi 4/n.y.blood/v6-7/sysent.c#include "../h/param.h" #include "../h/systm.h" /* * This table is the switch used to transfer * to the appropriate routine for processing a system call. * Each row contains the number of arguments expected * and a pointer to the routine. */ int alarm(); int mpxchan(); int chdir(); int chmod(); int chown(); int chroot(); int close(); int creat(); int dup(); int exec(); int exece(); int fork(); int fstat(); int getgid(); int getpid(); int getuid(); int gtime(); int gtty(); int ioctl(); int kill(); int link(); int mknod(); int nice(); int nosys(); int nullsys(); int open(); int pause(); int pipe(); int profil(); int ptrace(); int read(); int rexit(); int saccess(); int sbreak(); int seek(); int setgid(); int setuid(); int smount(); int ssig(); int stat(); int stime(); int stty(); int sumount(); int ftime(); int sync(); int sysacct(); int syslock(); int sysphys(); int tell(); int times(); int umask(); int unlink(); int utime(); int wait(); int write(); struct sysent sysent[64] = { 0, 0, nullsys, /* 0 = indir */ 1, 1, rexit, /* 1 = exit */ 0, 0, fork, /* 2 = fork */ 3, 1, read, /* 3 = read */ 3, 1, write, /* 4 = write */ 2, 0, open, /* 5 = open */ 1, 1, close, /* 6 = close */ 0, 0, wait, /* 7 = wait */ 2, 0, creat, /* 8 = creat */ 2, 0, link, /* 9 = link */ 1, 0, unlink, /* 10 = unlink */ 2, 0, exec, /* 11 = exec */ 1, 0, chdir, /* 12 = chdir */ 0, 0, gtime, /* 13 = time */ 3, 0, mknod, /* 14 = mknod */ 2, 0, chmod, /* 15 = chmod */ 3, 0, chown, /* 16 = chown; now 3 args */ 1, 0, sbreak, /* 17 = break */ 2, 0, stat, /* 18 = stat */ 4, 1, seek, /* 19 = seek; now 3 args */ 0, 0, getpid, /* 20 = getpid */ 3, 0, smount, /* 21 = mount */ 1, 0, sumount, /* 22 = umount */ 1, 1, setuid, /* 23 = setuid */ 0, 0, getuid, /* 24 = getuid */ 2, 2, stime, /* 25 = stime */ 4, 1, ptrace, /* 26 = ptrace */ 1, 1, alarm, /* 27 = alarm */ 2, 1, fstat, /* 28 = fstat */ 0, 0, pause, /* 29 = pause */ 2, 0, utime, /* 30 = utime */ 2, 1, stty, /* 31 = stty */ 2, 1, gtty, /* 32 = gtty */ 2, 0, saccess, /* 33 = access */ 1, 1, nice, /* 34 = nice */ 1, 0, ftime, /* 35 = ftime; formerly sleep */ 0, 0, sync, /* 36 = sync */ 2, 1, kill, /* 37 = kill */ 0, 0, nullsys, /* 38 = switch; inoperative */ 0, 0, nullsys, /* 39 = setpgrp (not in yet) */ 1, 1, tell, /* 40 = tell (v6 only) */ 2, 2, dup, /* 41 = dup */ 0, 0, pipe, /* 42 = pipe */ 1, 0, times, /* 43 = times */ 4, 0, profil, /* 44 = prof */ 0, 0, nosys, /* 45 = unused */ 1, 1, setgid, /* 46 = setgid */ 0, 0, getgid, /* 47 = getgid */ 2, 0, ssig, /* 48 = sig */ 0, 0, nosys, /* 49 = reserved for USG */ 0, 0, nosys, /* 50 = reserved for USG */ 1, 0, sysacct, /* 51 = turn acct off/on */ 3, 0, sysphys, /* 52 = set user physical addresses */ 1, 0, syslock, /* 53 = lock user in core */ 3, 0, ioctl, /* 54 = ioctl */ 0, 0, nosys, /* 55 = readwrite (in abeyance) */ 4, 0, mpxchan, /* 56 = creat mpx comm channel */ 0, 0, nosys, /* 57 = reserved for USG */ 0, 0, nosys, /* 58 = reserved for USG */ 3, 0, exece, /* 59 = exece */ 1, 0, umask, /* 60 = umask */ 1, 0, chroot,  /* 61 = chroot */ 0, 0, nosys, /* 62 = not used */ 0, 0, nosys /* 63 = used internally */ }; qiY4/n.y.blood/v6-7/trap.c#include "../h/param.h" #include "../h/systm.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/proc.h" #include "../h/reg.h" #include "../h/seg.h" #define EBIT 1 /* user error bit in PS: C-bit */ #define SETD 0170011 /* SETD instruction */ #define SYS 0104400 /* sys (trap) instruction */ #define USER 020 /* user-mode flag added to dev */ #define MEMORY ((physadr)0177740) /* 11/70 "memory" subsystem */ /* * Offsets of the user's registers relative to * the saved r0. See reg.h */ char regloc[9] = { R0, R1, R2, R3, R4, R5, R6, R7, RPS }; /* * Called from l40.s or l45.s when a processor trap occurs. * The arguments are the words saved on the system stack * by the hardware and software during the trap processing. * Their order is dictated by the hardware and the details * of C's calling sequence. They are peculiar in that * this call is not 'by value' and changed user registers * get copied back on return. * dev is the kind of trap that occurred. */ trap(dev, sp, r1, nps, r0, pc, ps) int *pc; dev_t dev; { register i; register *a; register struct sysent *callp; int (*fetch)(); time_t syst; syst = u.u_stime; u.u_fpsaved = 0; if ((ps&UMODE) == UMODE) dev |= USER; u.u_ar0 = &r0; switch(minor(dev)) { /* * Trap not expected. * Usually a kernel mode bus error. * The numbers printed are used to * find the hardware PS/PC as follows. * (all numbers in octal 18 bits) * address_of_saved_ps = * (ka6*0100) + aps - 0140000; * address_of_saved_pc = * address_of_saved_ps - 2; */ default: printf("ka6 = %o\n", ka6->r[0]); printf("aps = %o\n", &ps); printf("pc = %o ps = %o\n", pc, ps); printf("trap type %o\n", dev); panic("trap"); case 0+USER: /* bus error */ i = SIGBUS; break; /* * If illegal instructions are not * being caught and the offending instruction * is a SETD, the trap is ignored. * This is because C produces a SETD at * the beginning of every program which * will trap on CPUs without 11/45 FPU. */ case 1+USER: /* illegal instruction */ if(fuiword((caddr_t)(pc-1)) == SETD && u.u_signal[SIGINS] == 0) goto out; i = SIGINS; break; case 2+USER: /* bpt or trace */ i = SIGTRC; ps &= ~TBIT; break; case 3+USER: /* iot */ i = SIGIOT; break; case 5+USER: /* emt */ i = SIGEMT; break; case 6+USER: /* sys call */ u.u_error = 0; ps &= ~EBIT; a = pc; callp = &sysent[fuiword((caddr_t)(a-1))&077]; if (callp == sysent) { /* indirect */ a = (int *)fuiword((caddr_t)(a)); pc++; i = fuword((caddr_t)a); a++; if ((i & ~077) != SYS) i = 077; /* illegal */ callp = &sysent[i&077]; fetch = fuword; } else { pc += callp->sy_narg - callp->sy_nrarg; fetch = fuiword; if((ISV6) && (callp == &sysent[19])) /* v6 seek called directly */ pc--; } for (i=0; isy_nrarg; i++) u.u_arg[i] = u.u_ar0[regloc[i]]; for(; isy_narg; i++) u.u_arg[i] = (*fetch)((caddr_t)a++); u.u_dirp = (caddr_t)u.u_arg[0]; u.u_r.r_val1 = u.u_ar0[R0]; u.u_r.r_val2 = u.u_ar0[R1]; u.u_ap = u.u_arg; if (save(u.u_qsav)) { if (u.u_error==0) u.u_error = EINTR; } else { (*callp->sy_call)(); } if(u.u_error) { ps |= EBIT; u.u_ar0[R0] = u.u_error; } else { u.u_ar0[R0] = u.u_r.r_val1; u.u_ar0[R1] = u.u_r.r_val2; } goto out; /* * Since the floating exception is an * imprecise trap, a user generated * trap may actually come from kernel * mode. In this case, a signal is sent * to the current process to be picked * up later. */ case 8: /* floating exception */ stst(&u.u_fper); /* save error code */ psignal(u.u_procp, SIGFPT); return; case 8+USER: i = SIGFPT; stst(&u.u_fper); break; /* * If the user SP is below the stack segment, * grow the stack automatically. * This relies on the ability of the hardware * to restart a half executed instruction. * On the 11/40 this is not the case and * the routine backup/l40.s may fail. * The classic example is on the instruction * cmp -(sp),-(sp) */ case 9+USER: /* segmentation exception */ { int osp; osp = sp; if(backup(u.u_ar0) == 0) if(grow((unsigned)osp)) goto out; i = SIGSEG; break; } /* * The code here is a half-hearted * attempt to do something with all * of the 11/70 parity registers. * In fact, there is little that * can be done. */ case 10: case 10+USER: printf("parity\n"); if(cputype == 70) { for(i=0; i<4; i++) printf("%o ", MEMORY->r[i]); printf("\n"); MEMORY->r[2] = -1; if(dev & USER) { i = SIGBUS; break; } } panic("parity"); /* * Allow process switch */ case USER+12: goto out; /* * Locations 0-2 specify this style trap, since * DEC hardware often generates spurious * traps through location 0. This is a * symptom of hardware problems and may * represent a real interrupt that got * sent to the wrong place. Watch out * for hangs on disk completion if this message appears. */ case 15: case 15+USER: printf("Random interrupt ignored\n"); return; } psignal(u.u_procp, i); out: if(issig()) { psig(); } curpri = setpri(u.u_procp); if (runrun) qswtch(); if(u.u_prof.pr_scale) addupc((caddr_t)pc, &u.u_prof, (int)(u.u_stime-syst)); if (u.u_fpsaved) restfp(&u.u_fps); } /* * nonexistent system call-- set fatal error code. */ nosys() { u.u_error = EINVAL; } /* * Ignored system call */ nullsys() { } tqi34/n.y.blood/v6-7/user.h/* * The user structure. * One allocated per process. * Contains all per process data * that doesn't need to be referenced * while the process is swapped. * The user block is USIZE*64 bytes * long; resides at virtual kernel * loc 140000; contains the system * stack per user; is cross referenced * with the proc structure for the * same process. */ #define EXCLOSE 01 #define V6 0100 #define ISV6 (u.u_fpflag & V6) struct user { label_t u_rsav; /* save info when exchanging stacks */ int u_fper; /* FP error register */ int u_fpsaved; /* FP regs saved for this proc */ struct { int u_fpsr; /* FP status register */ double u_fpregs[6]; /* FP registers */ } u_fps; char u_segflg; /* IO flag: 0:user D; 1:system; 2:user I */ char u_error; /* return error code */ short u_uid; /* effective user id */ short u_gid; /* effective group id */ short u_ruid; /* real user id */ short u_rgid; /* real group id */ struct proc *u_procp; /* pointer to proc structure */ int *u_ap; /* pointer to arglist */ union { /* syscall return values */ struct { int r_val1; int r_val2; }; off_t r_off; time_t r_time; } u_r; caddr_t u_base; /* base address for IO */ unsigned int u_count; /* bytes remaining for IO */ off_t u_offset; /* offset in file for IO */ struct inode *u_cdir; /* pointer to inode of current directory */ struct inode *u_rdir; /* root directory of current process */ char u_dbuf[DIRSIZ]; /* current pathname component */ caddr_t u_dirp; /* pathname pointer */ struct direct u_dent; /* current directory entry */ struct inode *u_pdir; /* inode of parent directory of dirp */ int u_uisa[16]; /* prototype of segmentation addresses */ int u_uisd[16]; /* prototype of segmentation descriptors */ struct file *u_ofile[NOFILE]; /* pointers to file structures of open files */ char u_pofile[NOFILE]; /* per-process flags of open files */ int u_arg[5]; /* arguments to current system call */ unsigned u_tsize; /* text size (clicks) */ unsigned u_dsize; /* data size (clicks) */ unsigned u_ssize; /* stack size (clicks) */ label_t u_qsav; /* label variable for quits and interrupts */ label_t u_ssav; /* label variable for swapping */ int u_signal[NSIG]; /* disposition of signals */ time_t u_utime; /* this process user time */ time_t u_stime; /* this process system time */ time_t u_cutime; /* sum of childs' utimes */ time_t u_cstime; /* sum of childs' stimes */ int *u_ar0; /* address of users saved R0 */ struct { /* profile arguments */ short *pr_base; /* buffer base */ unsigned pr_size; /* buffer size */ unsigned pr_off; /* pc offset */ unsigned pr_scale; /* pc scaling */ } u_prof; char u_intflg; /* catch intr from sys */ char u_sep; /* flag for I and D separation */ struct tty *u_ttyp; /* controlling tty pointer */ dev_t u_ttyd; /* controlling tty dev */ struct { /* header of executable file */ int ux_mag; /* magic number */ unsigned ux_tsize; /* text size */ unsigned ux_dsize; /* data size */ unsigned ux_bsize; /* bss size */ unsigned ux_ssize; /* symbol table size */ unsigned ux_entloc; /* entry location */ unsigned ux_unused; unsigned ux_relflg; } u_exdata; char u_comm[DIRSIZ]; time_t u_start; char u_acflag; short u_fpflag; /* unused now, will be later */ short u_cmask; /* mask for file creation */ int u_stack[1]; /* kernel stack per user * extends from u + USIZE*64 * backward not to reach here */ }; extern struct user u; /* u_error codes */ #define EPERM 1 #define ENOENT 2 #define ESRCH 3 #define EINTR 4 #define EIO 5 #define ENXIO 6 #define E2BIG 7 #define ENOEXEC 8 #define EBADF 9 #define ECHILD 10 #define EAGAIN 11 #define ENOMEM 12 #define EACCES 13 #define EFAULT 14 #define ENOTBLK 15 #define EBUSY 16 #define EEXIST 17 #define EXDEV 18 #define ENODEV 19 #define ENOTDIR 20 #define EISDIR 21 #define EINVAL 22 #define ENFILE 23 #define EMFILE 24 #define ENOTTY 25 #define ETXTBSY 26 #define EFBIG 27 #define ENOSPC 28 #define ESPIPE 29 #define EROFS 30 #define EMLINK 31 #define EPIPE 32 #define EDOM 33 #define ERANGE 34 #q Ae\Ӛ 4/nijmegen/q tq4/nijmegen/contents- a DZ11 driver. Supports dial-up. - shared data area stuff. One module was missing in the previous mailing, namely: malloc.c. - fconv, a program that converts standard upper case Fortran to the UNIX Fortran conventions. - a version of restor that allows one to control the order in which files are put back on a file system. - an RK driver that features overlapping seeks for multiple drives and seek-ordering on each drive. q bql4/nijmegen/dz.4.th DZ IV 11/01/76 .sh NAME dz \*- DZ-11 communications multiplexer .sh DESCRIPTION Each line attached to the DZ-11 communications multiplexer behaves as described in tty (IV). Each line may independently be set to run at any of 16 speeds; see stty (II) for the encoding. In particular, codes 16, 17 and 18 have been added to supply 2000, 3600 and 7200 baud resp. The DZ-11 speed range is, in baud: 50, 75, 110, 134.5, 150, 300, 600, 1200, 1800, 2000, 2400, 3600, 4800, 7200, 9600. .s3 Default speed setting is 300 baud. Impossible speed setting requests to 'stty' will reset this default speed. .s3 See ttys (V) and the file '/etc/ttys' for standard line speeds at logon time. .sh FILES /dev/tty[0-7] .br /etc/ttys .sh "SEE ALSO" tty (IV), stty (I), stty (II), tty (IV), ttys (V) .sh AUTHOR H. J. Thomassen, Computer Graphics Group, Nijmegen Univ., the Netherlands. .sh BUGS q _q@'4/nijmegen/dz.c# /* * DZ-11A driver (for 8 lines max) * Adapted from Bell Lab's standard * DH and DHDM driver, with inspiration * from the DC11 driver. * A fair amount of code is duplicated. * If you have both this driver and a DH or DC * one resident, it is probably wise to try to * share code by modifying this one. * * To adapt this driver to a 16-line DZ-11, all references * to 'dzaddr' must be preceded by a decision (made somehow) * which one of the two Unibus-addresses to pick. * Furthermore, 'dzstatus' should be used to watch 16 carrier bits * now and routine 'dztimer' should be rewritten to make * it word-oriented instead of byte-oriented. * Watch out for the implied restriction that minor device number * equals the hardware line number currently. * * H.J. Thomassen, Computer Graphics Group, * Faculteit W & N, Toernooiveld * Nijmegen University, the Netherlands. * November 1976. * * This driver was released to the software * exchange since there seemed to be a need * for DZ-11 support. It has been running * at our installation for several days * without problems. However, this is not * a piece of software with a field proven * record. Please contact the author about * any flaws you may find. A better * version will be released if necessary as * soon as possible. */ #include "../conf.h" #include "../param.h" #include "../proc.h" #include "../tty.h" #include "../user.h" #define dzaddr 0167740 #define ndz11 8 /* number of lines supported <= 8 */ /* When changing configuration, be sure to update dzspeedtab too */ struct tty dz11[ndz11];/* allocate one tty.h structure for each line */ /* * hardware control bits */ #define bits6 010 /* char. length in bits */ #define bits7 020 #define bits8 030 #define twosb 040 /* want 1.5 or 2 stop bits */ #define penable 0100 /* enable parity */ #define opar 0200 /* odd parity if enabled */ #define ienable 040100 /* enable all intrpts except silo */ #define scenabl 040 /* master scan enable */ #define done 0200 /* receiver done */ #define xint 0100000 /* xmitter done */ #define dvalid 0100000 /* input data are valid */ #define ferror 020000 /* framing error on input char */ #define perror 010000 /* parity error on input char */ /**************************************************************** /* /* Attention: hardware requires most of the registers /* to be accessed by certain instructions in assembler only. /* Take care that the C-compiler generates proper code !!!!! /* /***************************************************************/ struct { /* read and write register lay-out */ int dzcsr; int x1; int dzstatus; }; struct { /* read only register lay-out */ int x2; int dzrbuf; char x3; char x4; char dzring; char dzcarr; }; struct { /* write only register lay-out */ int x5; int dzlpr; char x6; char x7; char dztbuf; char dzbrk; }; /* Note: it is wise to connect faster terminals to higher line numbers. */ char dzspeedtab[] { /* speed control bits for 'lpr' register (high byte) */ /* Index into the table is the same as the speed selector numbers for the DH11 (as is maintained in tp->t_speeds). The DZ-11 does not support 200 bps, ext A and ext B. It does support 2000, 3600 and 7200 bps, which will be accepted by stty as indices 16, 17 and 18. */ 0>>8, /* hang up */ 010000>>8, /* 50 baud */ 010400>>8, /* 75 baud */ 011000>>8, /* 110 baud */ 011400>>8, /* 134,5 baud */ 012000>>8, /* 150 baud */ 0>>8, /* no 200 baud */ 012400>>8, /* 300 baud */ 013000>>8, /* 600 baud */ 013400>>8, /* 1200 baud */ 014000>>8, /* 1800 baud */ 015000>>8, /* 2400 baud */ 016000>>8, /* 4800 baud */ 017000>>8, /* 9600 baud */ 0>>8, /* no ext. A */ 0>>8, /* no ext. B */ 014400>>8, /* 2000 baud */ 015400>>8, /* 3600 baud */ 016400>>8, /* 7200 baud */ }; char dztflag; /* remember whether timer got activated */ /* * Open a DZ-11 line */ dzopen(dev, flag) { register struct tty *tp; extern dzstart(); if (!dztflag) {dztimer(); dztflag++;} /* start watching carrier */ if ( dev.d_minor >= ndz11 ) {/* invalid minor dev. no */ u.u_error = ENXIO; return; } tp = &dz11[dev.d_minor]; tp->t_addr = dzstart; /* address of startup function */ tp->t_dev = dev; dzaddr->dzcsr =| ienable|scenabl; /* turn on the thing */ tp->t_state =| WOPEN|SSTART; /* internal state: wait for open */ if ((tp->t_state & ISOPEN) == 0) {/* fill tty.h with basic info */ tp->t_erase = CERASE; tp->t_kill = CKILL; tp->t_speeds= 7+(7<<8); /* default speed 300 baud */ tp->t_flags = ODDP|EVENP|ECHO|XTABS; /* defaults for STTY */ dzparam(tp); /* set stuff to DZ11 hardware */ } dzlopen(dev); /* open the line, and return when connection is there */ tp->t_state =& ~WOPEN; /* line is open now */ tp->t_state =| ISOPEN; if (u.u_procp->p_ttyp == 0) u.u_procp->p_ttyp = tp; /* hook this line to this process */ } /* * Close a DZ-11 line */ dzclose(dev) { register struct tty *tp; tp = &dz11[dev.d_minor]; dzlclose(dev); tp->t_state =& CARR_ON|SSTART; wflushtty(tp); } /* * Read from a DZ-11 line */ dzread(dev) { ttread( &dz11[dev.d_minor]); } /* * Write on a DZ-11 line */ dzwrite(dev) { ttwrite( &dz11[dev.d_minor]); } /* * DZ-11 receiver interrupt */ dzrint() { register struct tty *tp; register int c, line; while ((c=dzaddr->dzrbuf) < 0) { /* as long as valid char's come in */ line = ( (c>>8)&07 ); tp = &dz11[line]; /* get good tty struct via line no */ if ( tp >= &dz11[ndz11] ) continue; /* ignore invalid line numbers */ if ( tp->t_state & ISOPEN == 0) { /* was open done ok? */ if ( tp->t_state&WOPEN && dzaddr->dzcarr&(1<t_state =| CARR_ON; wakeup(tp); return; /* look out: tty not hooked to process yet */ } if ( c&perror ) continue; /* ignore char. w par. err. */ if ( c&ferror ) /* break key or bad speed */ if ( tp->t_flags & RAW ) c = 0; /* gtty must change speed */ else c = 0177; /* convert to 'del' (intr) */ ttyinput(c, tp); } } /* * DZ-11 transmitter interrupt */ dzxint() { extern ttrstrt(); register struct tty *tp; register int c, line; while ( (line=dzaddr->dzcsr) < 0) { /* as long as lines to serve */ line = (line>>8)&07; tp = &dz11[line]; if (( c= getc (&tp->t_outq) ) >= 0) { if ( c<0200 ) { /* if no delay wanted */ dzaddr->dztbuf = c;/* just send it */ goto out; } } /* if no more characters to xmit or a delay has to be generated, shut off that current DZ-11 line */ dzaddr->dzstatus =& ~(1<= 0200) { timeout(ttrstrt, tp, (c&0177)+6 ); tp->t_state =| TIMEOUT; } /* if this writer was sleeping on output overflow (ttwrite) or was waiting to drain (wflushtty), wake him up when low tide got reached or we drained all the way. (asleep-bit in t_state not used) */ out: if ((tp->t_outq.c_cc == 0) || (tp->t_outq.c_cc == TTLOWAT)) wakeup (&tp->t_outq); } } /* * Restart transmission on a DZ-11 line */ dzstart(atp) struct tty *atp; { register struct tty *tp; tp=atp; if (tp->t_state & TIMEOUT) return; /* we're still waiting t.o */ dzaddr->dzstatus =| (1<t_dev.d_minor); /* turn on xmit-enable bit scanner does the rest */ } /* * Set parameters from open or stty call to DZ-11 hardware registers */ dzparam(atp) struct tty *atp; { register struct tty *tp; register int lpr; tp=atp; spl5(); if (tp->t_speeds.lobyte == 0) { /* hang up the line? */ tp->t_flags =| HUPCL; dzlclose(tp->t_dev); return; } dzaddr->dzcsr.lobyte =| ienable; /* enable interrupts */ /* build bit pattern to send to line param register */ lpr = (dzspeedtab[tp->t_speeds.lobyte]<<8) + tp->t_dev.d_minor; /* set up parity bits: if stty will accept both odd and even tell line to accept all 8 bits and forget about checking. otherwise, enable parity checking and set whatever desired. */ if (tp->t_flags & EVENP) if (tp->t_flags & ODDP) lpr =| bits8; else lpr =| bits7|penable; else lpr =| bits7|penable|opar; /* if appropriate, insert here setting of twosb-bit etc. */ dzaddr->dzlpr = lpr; spl0(); } /* * STTY and GTTY for DZ-11 */ dzsgtty(dev, av) int *av; { register struct tty *tp; register int r; tp = &dz11[dev.d_minor]; if ( ttystty(tp, av) ) return; if (dzspeedtab[tp->t_speeds.lobyte] == 0) /* catch bad speeds */ tp->t_speeds= 7+(7<<8); /* default speed 300 baud */ dzparam(tp); } /* * Open one of the lines, and return when connection is established. */ dzlopen(dev) { register struct tty *tp; register thisline; tp = &dz11[dev.d_minor]; thisline = (000401<<(dev.d_minor)); dzaddr->dzstatus =| thisline; /* set data term. ready and xmit enb */ if (dzaddr->dzcarr & thisline) /* make sure this expands as BITB */ tp->t_state =| CARR_ON; while ((tp->t_state & CARR_ON) == 0) sleep (&tp->t_rawq, TTIPRI); } /* * Close one of the DZ-11 lines */ dzlclose(dev) { register struct tty *tp; register line; tp = &dz11[dev.d_minor]; if (tp->t_flags & HUPCL) { /* if stty has hupcl mode, */ line = (1<dzstatus.hibyte =& ~line; /* must generate BICB */ } } /* * Watch the carrier every second (time-out loop). * Hang up people loosing their carrier, wake up people * sleeping on a carrier to come in. */ int dzstatus; dztimer() { register struct tty *tp; register char *c; register int diff; int mask, line; if ( (c=dzaddr->dzcarr) != dzstatus ) { mask = 0200; line = 7; diff = ((c^dzstatus)<<8); do { if (diff < 0) { tp = &dz11[line]; wakeup(tp); if (!(c&mask)) { if ((tp->t_state & WOPEN) == 0) { signal (tp, SIGHUP); flushtty(tp); } tp->t_state =& ~CARR_ON; } else { tp->t_state =| CARR_ON; } } line--; mask =>> 1; } while ( diff =<< 1); dzstatus = c; } timeout (dztimer, 0, HZ); } q  ܗq4/nijmegen/fconv.1.th FCONV I 04/04/77 .sh NAME fconv \*- convert to UNIX Fortran conventions .sh SYNOPSIS .bd fconv [ file ] .sh DESCRIPTION Fconv splits the file .bd file , or its standard input if no file name is given, into separate files, each containing one Fortran module, as is required by fc(I). At the same time it does the following conversions, in the order given: .sp 1 .lp +2 2 - truncate each line to 72 characters. .lp +2 2 - remove carriage return before newline. .lp +2 2 - remove trailing blanks. .lp +2 2 - throw away blank lines. .lp +2 2 - convert upper case to lower case. .lp +2 2 - change continuation lines to the UNIX Fortran convention. .lp +2 2 - replace blanks preceding column 7 with a tab. .i0 .sp 1 The name of the output file for each module is the name of the routine (up to 6 characters) followed by '.f'. The name of a block data module is 'blockdata.f', and if the module has no recognizable name, it will be called 'main.f'. .sh AUTHOR George Rolf, Computer Graphics Group, University of Nijmegen, The Netherlands. .sh FILES .nf .ta 12 tmpconv# temporary name of output file. *.f output files. .sh "SEE ALSO" fc (I), trunc (I). .sh BUGS q wܗq(4/nijmegen/fconv.c# char tempfile[14] "tmpfconv00000"; int tempexist 0; #define lbuf 72 char buf[lbuf+1], sbuf[lbuf+1]; main(argc,argv) char **argv; { register i,j; char *b; int fout, ft, np; static int finbuf[259]; extern stop(); i= getpid(); b= &tempfile[sizeof tempfile - 1]; for(j= 5; j != 0; j--) { *--b= i%10 + '0'; i=/ 10; } for(j= 1; j <= 3; j++) signal(j,stop); if(argc > 1) { if(fopen(argv[1],finbuf) < 0) { printf("cannot open %s\n",argv[1]); stop(); } } while(1) { i= getcon(buf,lbuf,finbuf); if(i <= 0) stop(); ft= -1; if(buf[0] == 'c') { ft= creat(tempfile,0600); if(ft < 0) { printf("Cannot create %s\n",tempfile); stop(); } tempexist++; while(buf[0] == 'c') { write(ft,buf,i); write(ft,"\n",1); i= getcon(buf,lbuf,finbuf); if(i <= 0) { printf("unexpected eof\n"); stop(); } } } compress(buf,sbuf,i); np= name(sbuf,i); buf[i]= 0; printf("%8s: %s\n",np,buf); if(ft >= 0) { unlink(np); if(link(tempfile,np)) { printf("cannot link %s and %s\n",tempfile,np); stop(); } tempexist= 0; if(unlink(tempfile)) { printf("cannot unlink %s\n",tempfile); stop(); } fout= ft; } else { fout= creat(np,0666); if(fout < 0) { printf("Cannot create %s\n",np); stop(); } } while(1) { write(fout,buf,i); write(fout,"\n",1); if(compstr(sbuf,"end") == 0) break; i= getcon(buf,lbuf,finbuf); if( i <= 0) { printf("unexpected eof\n"); stop(); } compress(buf,sbuf,i); } close(fout); } } getcon(b,lb,f) char *b; { register i; do { i= getline(b,lb,f); if(i < 0) return(i); i= convert(b,i); } while(i == 0); return(i); } stop() { if(tempexist) if(unlink(tempfile) < 0) printf("Cannot unlink %s\n",tempfile); exit(); } copy(f1,f2) { register i; static int b[256]; while(1) { i= read(f1,b,512); if(i <= 0) return; write(f2,b,i); } } convert(b,l) char *b; { register char *i, *j; register char c; if(l <= 0) return(l); /* truncate */ if(b[l-1] == '\r') l=- 1; for(i= &b[l-1]; (*i == ' ') && (i >= b); i--) l--; /* lower case */ for(i= &b[0]; i < &b[l]; i++) if((*i >= 'A') && (*i <= 'Z')) *i =+ ('a' - 'A'); if((b[0] != 'c') && (l >= 6)) { /* continuation */ switch(b[5]) { case ' ': break; case '0': b[5]= ' '; break; default: b[5]= ' '; b[0]= '&'; } /* tab to col 7 */ for(i= &b[5]; (*i == ' ') && (i >= &b[0]); i--); *++i= '\t'; if(i < &b[5]) { l=- (&b[5]-i); i++; j= &b[6]; while(i < &b[l]) *i++= *j++; } } return(l); } compress(b,bc,l) char *b, *bc; { register i,j,c; j= 0; for(i= 0; i < l; i++) if((c= b[i]) != ' ') if( c != '\t') bc[j++]= c; bc[j]= 0; return(j); } char *subheader[] { "subroutine", "function", "integerfunction", "realfunction", "doubleprecisionfunction", "blockdata", 0 }; name(b,l) char *b; { register i,j; char *x; static char fn[9]; x= b; switch(comphead(&x,subheader)) { case 0: case 1: case 2: case 3: case 4: i= alphanstr(x,l-(x-b)); if(i > 6) i= 6; for(j= 0; j < i; j++) fn[j]= x[j]; fn[j++]= '.'; fn[j++]= 'f'; fn[j++]= '\0'; return(fn); case 5: return("blockdata.f"); default: return("main.f"); } } alphanstr(b,l) char *b; { register i,c; for(i= 0; i < l; i++) { c= b[i]; if(! (((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')) )) break; } return(i); } getline(b,l,f) char *b; { register i,k,c; k= 0; while(1) { switch(c = getc(f)) { case -1: return(-1); case '\n': return(k); case '\t': i= k+8; i=- i%8; for(; k < i;) { if(k >= l) goto bend; b[k++]= ' '; } break; default: if(k >= l) goto bend; b[k++]= c; } } bend: while((c = getc(f)) != -1) if(c == '\n') return(k); return(-1); } compstr(a,b) char *a, *b ; { register char *x, *y ; x= a ; y= b ; while( *x && *y ) if( *(x++) != *(y++) ) return(-1) ; return(((*x || *y)? -1 : 0)) ; } comphead(str,list) char **list, **str; { register i; char *s; s= *str; i= 0; while(*list) { if(comph(&s,*list) == 0) { *str= s; return(i); } i++; list++; } return(-1); } comph(a,b) char **a, **b; { register char *x, *y; x= *a; y= b; while(*x && *y) { if(*x++ != *y++) return(-1); } if(*y == 0) { *a= x; return(0); } return(-1); } q ܗqK 4/nijmegen/restor.8.th RESTOR VIII 11/24/73 .sh NAME restor \*- incremental file system restore .sh SYNOPSIS .bd restor key [ arguments ] .sh DESCRIPTION .it Restor is used to read magtapes dumped with the .it dump command. The .it key argument specifies what is to be done. .it Key is a character from the set .bd trxwo. .s3 .lp +5 3 \fBt\fR The date that the tape was made and the date that was specified in the .it dump command are printed. A list of all of the i-numbers on the tape is also given. .s3 .lp +5 3 \fBr\fR The tape is read and loaded into the file system specified in .it arguments. This should not be done lightly (see below). .s3 .lp +5 3 \fBx\fR Each file on the tape is individually extracted into a file whose name is the file's i-number. If there are .it arguments, they are interpreted as i-numbers and only they are extracted. .s3 .lp +5 3 \fBc\fR If the tape overflows, increment the last character of its name and continue on that drive. (Normally it asks you to change tapes.) .s3 .lp +5 3 \fBf\fR Read the dump from the next argument file instead of the tape. .s3 .lp +5 3 \fBi\fR All read and checksum errors are reported, but will not cause termination. .s3 .lp +5 3 \fBw\fR In conjunction with the .bd x option, before each file is extracted, its i-number is typed out. To extract this file, you must respond with .bd y. .s3 .lp +5 3 \fBo\fR The next file argument is a list of i-node numbers to be allocated first on the file system. If the first characters of each line of the file consist of digits, these are taken to be i-node numbers. The remainder of the line is ignored. With the r option this option is used to control the location of files on a file system. .s3 .i0 The .bd x option is used to retrieve individual files. If the i-number of the desired file is not known, it can be discovered by following the file system directory search algorithm. First retrieve the .it root directory whose i-number is 1. List this file with .it "ls \*-fi 1." This will give names and i-numbers of sub-directories. Iterating, any file may be retrieved. .s3 The .bd r option should only be used to restore a complete dump tape onto a clear file system or to restore an incremental dump tape onto this. Thus .s3 /etc/mkfs /dev/rk1 4872 .br restor r /dev/rk1 .s3 is a typical sequence to restore a complete dump. Another .it restor can be done to get an incremental dump in on top of this. .s3 A .it dump followed by a .it mkfs and a .it restor is used to change the size of a file system. .s3 The combination of options .it ro with a full dump to an empty file system is used to get files on a file system in a certain order. Ncheck(VIII) may be used to obtain a list of i-node numbers against file names. The output of ncheck, edited and sorted as required, can be used as an o-file. .sh FILES /dev/mt0 .sh "SEE ALSO" ls (I), dump (VIII), mkfs (VIII), clri (VIII) .sh DIAGNOSTICS There are various diagnostics involved with reading the tape and writing the disk. There are also diagnostics if the i-list or the free list of the file system is not large enough to hold the dump. .s3 If the dump extends over more than one tape, it may ask you to change tapes. Reply with a new-line when the next tape has been mounted. .sh BUGS There is redundant information on the tape that could be used in case of tape reading problems. Unfortunately, .it restor's approach is to exit if anything is wrong. hq ܗq$4/nijmegen/restor.c# /* * restore from incremental dumps * * changed for ordered restores by George Rolf. Doc # 52 ********** */ char *dargv[] { 0, "t", 0 }; char *ifile; char *ofile; #include "/usr/sys/ino.h" #include "/usr/sys/filsys.h" struct filsys sblock; int isize; int *talist; int fi; int buf[256]; int dbuf[256]; int cbuf[256]; char *date[2]; char *ddate[2]; int fo; int pher; char *tsize 15000; int iflg; int wflg; int cflg; char file[10]; int ilist[100]; /* Next 2 lines inserted. Doc # 52 *******/ char *numfile; int fnbuf[259]; main(argc, argv) char **argv; { char *key; register *tap, *p; register struct inode *ip; int i, com, sz, *q, l; ifile = "/dev/mt0"; if(argc == 1) { argv = dargv; for(argc = 1; dargv[argc]; argc++); } argc--; argv++; key = *argv; while(*key) switch(*key++) { default: printf("bad character in key\n"); exit(); /* Next 4 lines inserted. Doc # 52 *******/ case 'o': argv++; argc--; numfile = *argv; case 't': case 'r': case 'x': com = key[-1]; continue; case 'i': iflg++; continue; case '-': continue; case 'c': cflg++; continue; case 'f': argv++; argc--; ifile = *argv; continue; case 'w': wflg++; continue; } otape(); sread(buf, 0); tap = buf; isize = *tap++; *tap++; /* fsize */ date[0] = *tap++; date[1] = *tap++; ddate[0] = *tap++; ddate[1] = *tap++; tsize = *tap++; i = size(0, isize*32); talist = sbrk(i*512); tap = talist; while(i--) { tread(tap, 0); tap =+ 256; } switch(com) { case 't': l = 0; com = 0; pdate(ddate); pdate(date); tap = talist; for(i=0; i 60) { printf("\n"); l = 0; } else printf(","); com = 0; } else if(com == 0) com = i+1; } if(com) printf("%l-\n", com); printf("\n"); exit(); case 'r': /* Next line inserted. Doc # 52 *******/ case 'o': if(argc <= 1) { printf("no filesystem name\n"); exit(); } /* Next 5 lines inserted. Doc # 52 *******/ if(com == 'o') if(fopen(numfile,fnbuf) < 0) { printf("Cannot open %s\n",numfile); exit(0); } ofile = argv[1]; fo = open(ofile, 2); if(fo < 0) { printf("can not open %s\n", ofile); exit(); } printf("last chance before scribbling on %s\n", ofile); getchar(); dread(1, &sblock); /* Next inserted. Doc # 52 *******/ if(com == 'o') while((i = getnum()) != -1) { if((i > 0) && (i <= isize*16) && (i <= sblock.s_isize*16)) { sz = talist[i-1]; if(sz > 0) { ip= buf; dread((i-1)/16+2, ip); dealoc(&(ip[(i-1)%16])); restor(&(ip[(i-1)%16]), sz-1, 1); dwrite((i-1)/16+2, ip); continue; } } /* else else */ printf("inode %d invalid or not on tape\n",i); printf("type newline to continue"); getchar(); } tap = talist; for(i=0; i= isize) break; dread(i+2, buf); for(ip = &buf[0]; ip < &buf[256]; ip++) { sz = *tap++; if(sz == 0) continue; dealoc(ip); if(sz == -1) { for(p = ip; p < &ip->i_mtime[2]; ) *p++ = 0; continue; } sread(dbuf, 0); q = dbuf; for(p = ip; p < &ip->i_mtime[2]; ) *p++ = *q++; /* Next line changed. Doc # 52 *******/ restor(ip, sz-1, 0); } dwrite(i+2, buf); } dwrite(1, &sblock); com = 0; for(; i < isize; i++) for(l = 0; l < 16; l++) { sz = *tap++; if(sz != 0 && sz != -1) com++; } if(com) printf("%l files not restored - small ilist\n", com); exit(); case 'x': i = 0; tap = ilist; while(argc > 1) { i++; sz = number(argv[1]); argv++; argc--; if(sz <= 0 || sz >=isize*16) { printf("%l not in range\n", sz); continue; } if(talist[sz-1] == 0) { printf("%l not dumped\n", sz); continue; } if(talist[sz-1] == -1) { printf("%l does not exist\n", sz); continue; } *tap++ = sz; } if(i != 0 && ilist[0] == 0) exit(); tap = talist; for(i=1; i<=isize*16; i++) { if(ilist[0] != 0) { for(sz=0; ilist[sz]; sz++) if(ilist[sz] == i) goto yes; sz = *tap++; no: if(sz == -1) sz = 0; while(sz--) tread(dbuf, 1); continue; } yes: sz = *tap++; if(sz == 0 || sz == -1) continue; fo = dwait(i); if(fo < 0) goto no; sz--; sread(buf, 0); ip = buf; while(sz--) { tread(dbuf, 0); com = 512; if(ip->i_size0 == 0 && ip->i_size1 < 512) com = ip->i_size1; write(fo, dbuf, com); if(com > ip->i_size1) ip->i_size0--; ip->i_size1 =- com; } close(fo); chmod(file, ip->i_mode); chown(file, ip->i_uid); } exit(); } } dealoc(p) struct inode *p; { register struct inode *ip; register i, j; int k; int xbuf[256], ybuf[256]; ip = p; if(ip->i_mode & (IFCHR&IFBLK)) return; for(i=7; i>=0; i--) if(ip->i_addr[i]) { if(ip->i_mode&ILARG) { dread(ip->i_addr[i], xbuf); for(j=255; j>=0; j--) if(xbuf[j]) { if(i == 7) { dread(xbuf[j], ybuf); for(k=255; k>=0; k--) if(ybuf[k]) free(ybuf[k]); } free(xbuf[j]); } } free(ip->i_addr[i]); } } /* Next line changed. Doc # 52 *******/ restor(p, sz, dum) struct inode *p; { register struct inode *ip; register i, j; int xbuf[256]; ip = p; if(ip->i_mode & (IFCHR&IFBLK)) return; for(i=0; i<8; i++) ip->i_addr[i] = 0; if(sz <= 8) { for(i=0; ii_addr[i] = (dum ? alloc() : rcop()); ip->i_mode =& ~ILARG; return; } for(i=0; i<256; i++) xbuf[i] = 0; for(j=0; sz >= 256; j++) { if(j <= 7) ip->i_addr[j] = alloc(); if(j >= 7) xbuf[j-7] = alloc(); for(i=0; i<256; i++) /* Next line changed. Doc # 52 *******/ dbuf[i] = (dum ? alloc() : rcop()); if(j < 7) dwrite(ip->i_addr[j], dbuf); else dwrite(xbuf[j-7], dbuf); sz =- 256; } if(sz) { if(j <= 7) ip->i_addr[j] = alloc(); if(j >= 7) xbuf[j-7] = alloc(); for(i=0; ii_addr[j], dbuf); else dwrite(xbuf[j-7], dbuf); } if(j >= 7) dwrite(ip->i_addr[7], xbuf); ip->i_mode =| ILARG; } rcop() { register b; b = alloc(); tread(cbuf, 0); dwrite(b, cbuf); return(b); } pdate(d) int *d; { if(d[0] == 0 && d[1] == 0) printf("the epoch\n"); else printf(ctime(d)); } dread(bno, b) { seek(fo, bno, 3); if(read(fo, b, 512) != 512) { printf("disk read error %l\n", bno); exit(); } } dwrite(bno, b) { seek(fo, bno, 3); if(write(fo, b, 512) != 512) { printf("disk write error %l\n", bno); exit(); } } sread(b, flag) int *b; { register i, s, *p; tread(b, flag); if(flag) return; i = 256; s = 0; p = b; while(i--) s =+ *p++; if(s != 031415) { printf("checksum error\n"); if(!iflg) exit(); } } tread(b, flag) int *b; { register c; static char *pta, *ata, ctflg; if(pta++ >= tsize) { pta = 1; ata = 0; close(fi); otape(); ctflg++; } if(flag) return; if(ctflg) { printf("change tapes\n"); if(ctflg > 1) printf("skip %d tapes\n", ctflg-1); while((c = getchar()) != '\n') if(c == 0) exit(); ctflg = 0; } ata++; if(iflg) for(; pta != ata; ata++) read(fi, b, 512); if(pta != ata) { seek(fi, pta-ata, 4); ata = pta; } if(read(fi, b, 512) != 512) { printf("tape read error %l\n", ata-1); if(!iflg) exit(); for(c=0; c<256; c++) b[c] = 0; } } number(s) char *s; { register n, c; n = 0; while(c = *s++) { if(c<'0' || c>'9') continue; n = n*10+c-'0'; } return(n); } size(s0, s1) { register s; extern ldivr; s = ldiv(s0&0377, s1, 512); if(ldivr) s++; return(s); } otape() { register char *p; fi = open(ifile, 0); if(fi < 0) { printf("can not open %s\n", ifile); exit(); } if(!cflg) return; p = ifile; while(*p++) ; p[-2]++; } dwait(ino) { register i; dconv(ino, file); loop: if(wflg) { printf("%s ", file); i = getchar(); if(i == 'x') exit(); if(i == '\n') return(-1); if(i != 'y') goto flush; i = getchar(); if(i != '\n') { flush: while((i=getchar()) != '\n') if(i == '\0') exit(); goto loop; } } i = creat(file, 0666); return(i); } dconv(n, p) char *p; { register i; if(i = ldiv(0, n, 10)) p = dconv(i, p); *p++ = lrem(0, n, 10) + '0'; *p = '\0'; return(p); } alloc() { register b, i; i = --sblock.s_nfree; if(i<0 || i>=100) { printf("bad freeblock\n"); exit(); } b = sblock.s_free[i]; if(b == 0) { printf("out of freelist\n"); exit(); } if(sblock.s_nfree <= 0) { dread(b, cbuf); sblock.s_nfree = cbuf[0]; for(i=0; i<100; i++) sblock.s_free[i] = cbuf[i+1]; } return(b); } free(in) { register i; if(sblock.s_nfree >= 100) { cbuf[0] = sblock.s_nfree; for(i=0; i<100; i++) cbuf[i+1] = sblock.s_free[i]; sblock.s_nfree = 0; dwrite(in, cbuf); } sblock.s_free[sblock.s_nfree++] = in; } /* Next routine inserted. Doc # 52 *******/ getnum() { register i,j; static char b[20]; static int eof; if(eof) return(-1); for(i= 0; i<19; i++) { j= getc(fnbuf); if((j < '0') || (j > '9')) break; b[i]= j; } b[i]= 0; while((j != '\n') && (j != -1)) j= getc(fnbuf); if(j == '\n') return(number(b)); else { eof++; return(-1); } } .q (ݗq+4/nijmegen/rk.c# /* */ /* * Seek-optimizing RK disk driver. * * Derived from the driver by Bill Mayhew and Brent Byer, * The Children's Museum, Boston. Only this version's * author is to be blamed for bugs, errors, flaws, omissions * and other causes of complaint. * * This version by: * George Rolf, * Computer Graphics Group. * Toernooiveld, * Nijmegen, The Netherlands. * * The driver has the following characteristics: * 1. Multiple seek and overlap with I/O. * 2. Ordering of seeks into one-way sweeps from high to low * cylinder adresses. Unlike two-way sweeps, this * strategy will give equal chances to users at the ends * and in the middle of the sweeps. At the same time, * it will prevent a process from * monopolizing the disk for more than one cylinder at a time. * 3. The arm that just completed an I/O operation is given * preference when selecting a new block to transfer. * This will help improving throughput by having consecutive * file blocks two or more disk blocks apart. * 4. There is no sector optimization in the disk driver itself. * 5. Provisions have been made for multiple unit-single arm disk drives. * 6. Mr. Mayhew's disk layout has not been implemented in * this driver. * * When adding disk units, the constants NRK and NARMS have to * be increased, and the array rkarm has to be expanded with one queue * pointer for every logical unit added. The array rkbias is used in the * cylinder queuing algorithm. It must have a non-zero entry for the second * (logical) unit on the same platter. The entry is 1 for disks with the * 2 units' tracks interleaved on the platter (Diablo Series 400), * and 0100000 for the units separated on the platter. (DEC RKo5F) * Code to use a double-density disk as one UNIX device has * not been implemented; it can easily be inserted in the neighbourhood of * the comment "mapping for various formats". Note that the indices for rkq * bear no relation whatsoever with the hardware. All associations * between drive numbers and queues are via the array rkarm and the buf * headers. * * Note that your controller may not digest SEEK commands in a proper way. * Our own RK11-C (rack mounted type) gives seek-completes for all drives * that are on cylinder, not just the one for which the seek was * issued. The driver doesn't mind, unless NRK is smaller than the actual * number of drives present. Others have reported on RK11-D's (the SU mounted * tye) giving non-existent drive errors. Sometimes DEC ECO #M7255-C0009 seems * to cure the problem. * * The code for the interleaved file systems (v. RK(IV)) has not been * tested; neither was the code for double-density disks. */ #include "../param.h" #include "../buf.h" #include "../systm.h" #include "../conf.h" #include "../user.h" #define RKADDR 0177400 #define NRK 4 /* number of logical units */ #define NARMS 3 /* number of independent arms */ #define NRKBLK 4872 #define CRESET 0 #define GO 01 #define SEEK 010 #define DRESET 014 #define IENABLE 0100 #define CTLRDY 0200 #define SEEKCMP 020000 struct { int rkds; int rker; int rkcs; int rkwc; int rkba; int rkda; }; struct devtab rktab; struct buf rrkbuf; /* RK disk queues; one queue per arm. */ struct rkq { struct buf *rk_bufp; char *rk_lcyl; char rk_errcnt; char rk_seek; } rkq[NARMS]; struct rkq *rk_ap; /* pointer to queue currently active. */ struct rkq *rkarm[NRK] {&rkq[0],&rkq[1],&rkq[2],&rkq[2]}; char *rkbias[NRK] { 0, 0, 0, 0100000}; #define rkcyl av_back #define b_rkda b_resid rkstrategy(abp) struct buf *abp; { register struct buf *bp; register char *p1, *p2; char *c; int d; bp = abp; if(bp->b_flags&B_PHYS) mapalloc(bp); p2 = bp->b_blkno; p1 = bp->b_dev.d_minor; /* check validity */ d = p1-7; if( d <= 0 ) d = 1; if((p1&07) >= NRK || p2 >= d*NRKBLK) { bp->b_flags =| B_ERROR; iodone(bp); return; } /* mapping for various formats. */ if(p1&010) { p1 =& 07; d = lrem(p2, p1); p2 = ldiv(p2, p1); } else d = p1; /* Now d contains the logical drive, and p2 the block number */ bp->av_forw = 0; /* calculate drive, cylinder and sector. */ p1 = (p2/24)<<5; bp->rkcyl = p1 | rkbias[d]; /* get sector number (0-11) in bits 3 to 0, */ /* and surface number in bit 4 */ p2 =% 24; if( p2 >= 12 ) p2 =+ 4; bp->b_rkda = (d<<13)|p1|p2; spl5(); p2 = rkarm[d]; /* put the request into the queue. * the head of the queue is the block currently selected. * blocks are in order of decreasing cylinder number. foll- * owing the blocks of the current sweep are the ones for the * next sweep, again in cylinder order. */ if((p1 = p2->rk_bufp) == NULL) { /* queue was empty */ p2->rk_bufp = bp; if(rk_ap == NULL) rkstart(); } else { c = p2->rk_lcyl; p2 = p1->av_forw; if(bp->rkcyl > c) while(p2) { if( p2->rkcyl > c) break; p1 = p2; p2 = p1->av_forw; } while(p2) { if(p2->rkcyl < bp->rkcyl) break; p1 = p2; p2 = p1->av_forw; } bp->av_forw = p2; p1->av_forw = bp; } spl0(); } rkstart() { register struct buf *bp; register struct rkq *qp; for(qp = rkq; qp < &rkq[NARMS]; qp++) if((!qp->rk_seek) && (bp = qp->rk_bufp)) { if(bp->rkcyl == qp->rk_lcyl) { if( rk_ap == NULL ) rk_ap = qp; } else { RKADDR->rkda = bp->b_rkda; RKADDR->rkcs = IENABLE|SEEK|GO; while((RKADDR->rkcs&CTLRDY) == 0); qp->rk_lcyl = bp->rkcyl; qp->rk_seek = 1; } } if( rk_ap ) { bp = rk_ap->rk_bufp; devstart(bp, &RKADDR->rkda, bp->b_rkda, 0); } } rkintr() { register struct buf *bp; register struct rkq *qp; register n; if (RKADDR->rkcs < 0) { /* error bit */ rkerror(); } if(RKADDR->rkcs & SEEKCMP) { n = (RKADDR->rkds >> 13) & 07; if( n >= NRK ) rkerror(); else (*(rkarm[n])).rk_seek = 0; } if(qp = rk_ap) { /* this must be an I/O completion interrupt */ bp = qp->rk_bufp; qp->rk_bufp = bp->av_forw; bp->b_resid = 0; iodone(bp); qp->rk_errcnt = 0; bp = qp->rk_bufp; if((bp == NULL) || (bp->rkcyl != qp->rk_lcyl)) rk_ap = NULL; } rkstart(); } rkerror() { register struct buf *bp; register struct rkq *qp; if(rk_ap)  deverror(rk_ap->rk_bufp,RKADDR->rker,RKADDR->rkds); else printf("rkerr %o %o %o\n", RKADDR->rkcs,RKADDR->rker,RKADDR->rkds); for( qp = rkq; qp < &rkq[NARMS]; qp++) qp->rk_seek = 0; RKADDR->rkcs = CRESET|GO; while((RKADDR->rkcs&CTLRDY) == 0) ; if( qp = rk_ap ) { bp = qp->rk_bufp; if (++qp->rk_errcnt <= 10) rk_ap = 0; else bp->b_flags =| B_ERROR; } } rkread(dev) { physio(rkstrategy, &rrkbuf, dev, B_READ); } rkwrite(dev) { physio(rkstrategy, &rrkbuf, dev, B_WRITE); } (q AC\Ӛ4/nijmegen/sdaq Rݗq4/nijmegen/sda/malloc.c# /* */ /* 2 lines added; doc # 13-II */ #include "../param.h" #include "../systm.h" /* * Structure of the coremap and swapmap * arrays. Consists of non-zero count * and base address of that many * contiguous units. * (The coremap unit is 64 bytes, * the swapmap unit is 512 bytes) * The addresses are increasing and * the list is terminated with the * first zero count. */ struct map { char *m_size; char *m_addr; }; /* * Allocate size units from the given * map. Return the base of the allocated * space. * Algorithm is first fit. */ malloc(mp, size) struct map *mp; { register int a; register struct map *bp; for (bp = mp; bp->m_size; bp++) { if (bp->m_size >= size) { a = bp->m_addr; bp->m_addr =+ size; if ((bp->m_size =- size) == 0) do { bp++; (bp-1)->m_addr = bp->m_addr; } while ((bp-1)->m_size = bp->m_size); return(a); } } return(0); } /* * Free the previously allocated space aa * of size units into the specified map. * Sort aa into map and combine on * one or both ends if possible. */ mfree(mp, size, aa) struct map *mp; { register struct map *bp; register int t; register int a; a = aa; for (bp = mp; bp->m_addr<=a && bp->m_size!=0; bp++); if (bp>mp && (bp-1)->m_addr+(bp-1)->m_size == a) { (bp-1)->m_size =+ size; if (a+size == bp->m_addr) { (bp-1)->m_size =+ bp->m_size; while (bp->m_size) { bp++; (bp-1)->m_addr = bp->m_addr; (bp-1)->m_size = bp->m_size; } } } else { if (a+size == bp->m_addr && bp->m_size) { bp->m_addr =- size; bp->m_size =+ size; } else if (size) do { t = bp->m_addr; bp->m_addr = a; a = t; t = bp->m_size; bp->m_size = size; bp++; } while (size = t); } } /* * allocate swap space in coremap units. * routine added; document # 13-II. George Rolf. */ swall(size) { register a; a = malloc(swapmap,(size+7)/8); if( a == 0 ) panic("out of swap space"); return(a); } q;AR\ 4/purduenq:Aa\ 4/purdue/docaq9AD\ 4/purdue/srcaq8Ap\4/purdue/src/apllq6q4/purdue/src/apl/Cocc -c -O $1 $2 $3 $4 $5 $6 $7 q5mqb4/purdue/src/apl/CCcc -m -f -O -i $1 $2 $3 $4 $5 $6 $7 $8 $9 -u _main /usr2/apl/lib -ly echo apl generation complete q4|q4/purdue/src/apl/PRAPLnum stack) pop(); if(intflg) error("I"); putchar('\t'); a = rline(8); if(a == 0) term(); c = compile(a, 0); free(a); if(c == 0) continue; execute(c); free(c); } } intr() { intflg = 1; signal(2, intr); seek(0, 0, 2); } rline(s) { int rlcmp(); char line[CANBS]; register char *p; register c, col; char *cp; char *dp; int i,j; column = 0; col = s; p = line; loop: c = getchar(); if(intflg) error("I"); switch(c) { case '\0': case -1: return(0); case '\b': if(col) col--; goto loop; case '\t': col = (col+8) & ~7; goto loop; case ' ': col++; goto loop; case '\r': col = 0; goto loop; default: *p++ = col; *p++ = c; /* was and'ed with 0177... */ col++; goto loop; case '\n': ; } qsort(line, (p-line)/2, 2, rlcmp); c = p[-2]; if(p == line) c = 1; /* check for blank line */ *p = -1; c = alloc(c+3); col = -1; cp = c - 1; for(p=line; p[0] != -1; p=+2) { while(++col != p[0]) *++cp = ' '; *++cp = p[1]; while(p[2] == col) { if(p[3] != *cp) { i = *cp ; *cp = p[3]; break; } p =+ 2; } if(p[2] != col) continue; while(p[2] == col) { if(p[3] != *cp) goto yuck; p =+ 2; } i =| *cp << 8; for(j=0; chartab[j]; j++){ if(i == chartab[j]) { *cp = j | 0200; j = 0; break; } } if(j) { yuck: *cp = '\n'; pline(c,++col); error("Y error"); } } *++cp = '\n'; return(c); } rlcmp(a, b) char *a, *b; { register c; if(c = a[0] - b[0]) return(c); return(a[1] - b[1]); } pline(str, loc) char *str; { register c, l, col; col = 0; l = 0; do { c = *str++; l++; if(l == loc) col = column; putchar(c); } while(c != '\n'); if(col) { putto(col); putchar('^'); putchar('\n'); } } putto(col) { while(col > column+8) putchar('\t'); while(col > column) putchar(' '); } term() { unlink(LPFILE); unlink(WSFILE); putchar('\n'); aplmod(0); /* turn off APL mode */ exit(); } fix(d) data d; { register i; i = floor(d+0.5); return(i); } error(s) char *s; { register c; register char *cp; char bbb[2]; intflg = 0; if(ifile) { close(ifile); ifile = 0; } cp = s; while(c = *cp++) { if(c >= 'A' && c <= 'Z') { switch(c) { case 'I': c = "\ninterrupt"; break; case 'L': c = "L"; break; case 'C': c = "conformability"; break; case 'S': c = "syntax"; break; case 'R': c = "rank"; break; case 'X': c = "index"; break; case 'Y': c = "character"; break; case 'M': c = "memory"; break; case 'D': c = "domain"; break; case 'T': c = "type"; break; case 'E': c = "error"; break; case 'P': c = "programmer"; case 'B': c = "botch"; break; default: bbb[0] = c; bbb[1] = 0; c = bbb; } printf(c); continue; } putchar(c); } putchar('\n'); ibeam36 = funlc; funlc = 0; reset(); } printf(f, a) char *f; { register char *s, *cp; register *p; s = f; p = &a; while(*s) { if(s[0] == '%' && s[1] == 'd') { putn(*p++); s =+ 2; } else if(s[0] == '%' && s[1] == 's') { cp = *p++; s =+ 2; while(*cp) putchar(*cp++); } else putchar(*s++); } } putn(n) { register a; if(n < 0) { n = -n; if(n < 0) { printf("32768"); return; } putchar('-'); /* apl minus sign, was '"' */ } if(a=n/10) putn(a); putchar(n%10 + '0'); } getchar() { int c; c = 0; read(ifile, &c, 1); if(echoflg) write(1, &c, 1); if(protofile && ifile == 0) write(protofile, &c, 1); return(c); } putchar(c) { register i; switch(c) { case '\0': return; case '\b': if(column) column--; break; case '\t': column = (column+8) & ~7; break; case '\r': case '\n': column = 0; break; default: column++; } /* for encode numbers */ if(mencflg) { if(c != '\n') { mencflg = 1; *mencptr++ = c; } else if(mencflg > 1) mencptr =+ rowsz; else mencflg = 2; return; } if(intflg == 0) { if(c & 0200) { i = chartab[c & 0177]; putchar(i>>8); c = i & 0177; putchar('\b'); } write(1, &c, 1); if(protofile) write(protofile, &c, 1); } } fuzz(d1, d2) data d1, d2; { double f1, f2; f1 = d1; if(f1 < 0.) f1 = -f1; f2 = d2; if(f2 < 0.) f2 = -f2; if(f2 > f1) f1 = f2; f1 =* thread.fuzz; if(d1 > d2) { if(d2+f1 >= d1) return(0); return(1); } if(d1+f1 >= d2) return(0); return(-1); } pop() { dealloc(*--sp); } erase(np) struct nlist *np; { register *p; p = np->itemp; if(p) { switch(np->use) { case NF: case MF: case DF: for(; *p>0; (*p)--) free(p[*p]); } free(p); np->itemp = 0; } np->use = 0; } dealloc(p) struct item *p; { switch(p->type) { case DA: case CH: case QQ: case QD: case QC: free(p); } } newdat(type, rank, size) { register i; register struct item *p; if(rank > MRANK) error("max R"); i = sizeof *p + rank * SINT; if(type == DA) i =+ size * SDAT; else if(type == CH) i =+ size; p = alloc(i); p->rank = rank; p->type = type; p->size = size; p->index = 0; if(rank == 1) p->dim[0] = size; p->datap = &p->dim[rank]; return(p); } dupdat(ap) struct item *ap; { register struct item *p1, *p2; register i; p1 = ap; p2 = newdat(p1->type, p1->rank, p1->size); for(i=0; irank; i++) p2->dim[i] = p1->dim[i]; return(p2); } copy(type, from, to, size) char *from, *to; { register i; register char *a, *b; int s; if((i = size) == 0) return(0); a = from; b = to; if(type == DA) i =* SDAT; else if(type == IN) i =* SINT; s = i; do *b++ = *a++; while(--i); return(s); } fetch1() { register struct item *p; p = fetch(sp[-1]); sp[-1] = p; return(p); } fetch2() { register struct item *p; sp[-2] = fetch(sp[-2]); p = fetch(sp[-1]); sp[-1] = p; return(p); } fetch(ip) struct item *ip; { register struct item *p, *q; register i; int c; p = ip; loop: switch(p->type) { case QQ: free(p); c = rline(0); if(c == 0) error("eof"); for(i=0; c->c[i] != '\n'; i++) ; p = newdat(CH, 1, i); copy(CH, c, p->datap, i); goto loop; case QD: case QC: printf("L>\n\t"); i = rline(8); if(i == 0) error("eof"); c = compile(i, 1); free(i); if(c == 0) goto loop; i = pcp; execute(c); pcp = i; free(c); free(p); p = *--sp; goto loop; case DU: if(lastop != PRINT) error("no fn result"); case DA: case CH: p->index = 0; return(p); case LV: if(p->use != DA) error("used before set\n"); p = p->itemp; q = newdat(p->type, p->rank, p->size); copy(IN, p->dim, q->dim, p->rank); copy(p->type, p->datap, q->datap, p->size); return(q); default: error("fetch B"); } } topfix() { register struct item *p; register i; p = fetch1(); if(p->type != DA || p->size != 1) error("topval C"); i = fix(p->datap[0]); pop(); return(i); } bidx(ip) struct item *ip; { register struct item *p; p = ip; idx.type = p->type; idx.rank = p->rank; copy(IN, p->dim, idx.dim, idx.rank); size(); } size() { register i, s; s = 1; for(i=idx.rank-1; i>=0; i--) { idx.del[i] = s; s =* idx.dim[i]; } idx.size = s; return(s); } colapse(k) { register i; if(k < 0 || k >= idx.rank) error("collapse X"); idx.dimk = idx.dim[k]; idx.delk = idx.del[k]; for(i=k; i= idx.dim[i-1]) if(--i <= 0) return; } } access() { register i, n; n = 0; for(i=0; iindex; while(i >= p->size) { if(i == 0) error("getdat B"); i =- p->size; } if(p->type == DA) { d = p->datap[i]; } else if(p->type == CH) { d = p->datap->c[i]; } else error("getdat B"); i++; p->index = i; return(d); } putdat(ip, d) data d; struct item *ip; { register struct item *p; register i; p = ip; i = p->index; if(i >= p->size) error("putdat B"); if(p->type == DA) { p->datap[i] = d; } else if(p->type == CH) { p->datap->c[i] = d; } else error("putdat B"); i++; p->index = i; } aplmod(n) { char m[6]; if(n){ gtty(0, m); if(m[2] == '\b' || m[3] == '\b') printf("warning: erase char is ^H\n"); } } s2vect(ap) struct item *ap; { register struct item *p, *q; p = ap; q = newdat(p->type, 1, 1); q->datap = p->datap; q->dim[0] = 1; return(q); } struct nlist * nlook(name) char *name; { register struct nlist *np; for(np = nlist; np->namep; np++) if(equal(np->namep, name)) return(np); return(0); } q0qI 4/purdue/src/apl/a1.c#include "apl.h" execute(s) char *s; { register i; register data *dp; register struct item *p; struct item *p1; int j; data (*f)(), d; extern char *opname[]; if(debug) dump(s); loop: i = *s++; if(i != EOF) i =& 0377; lastop = i; if(debug && i >= 0) printf("exec %s\n", opname[i]); switch(i) { default: error("exec B"); case EOF: return; case EOL: pop(); goto loop; case COMNT: *sp++ = newdat(DA, 1, 0); goto loop; case ADD: case SUB: case MUL: case DIV: case MOD: case MIN: case MAX: case PWR: case LOG: case CIR: case COMB: case AND: case OR: case NAND: case NOR: f = exop[i]; p = fetch2(); p1 = sp[-2]; ex_dscal(0, f, p, p1); goto loop; case LT: case LE: case EQ: case GE: case GT: case NE: f = exop[i]; p = fetch2(); p1 = sp[-2]; ex_dscal(1, f, p, p1); goto loop; case PLUS: case MINUS: case SGN: case RECIP: case ABS: case FLOOR: case CEIL: case EXP: case LOGE: case PI: case RAND: case FAC: case NOT: f = exop[i]; p = fetch1(); if(p->type != DA) error("monadic T"); dp = p->datap; for(i=0; isize; i++) { *dp = (*f)(*dp); dp++; } goto loop; case MEPS: /* execute */ case MENC: /* monadic encode */ case DRHO: case DIOT: case EPS: case REP: case BASE: case DEAL: case DTRN: case CAT: case CATK: case TAKE: case DROP: case DDOM: case MDOM: case GDU: case GDUK: case GDD: case GDDK: case COM: case COM0: case COMK: case EXD: case EXD0: case EXDK: case ROT: case ROT0: case ROTK: case MRHO: case MTRN: case RAV: case RAVK: case RED: case RED0: case REDK: case SCAN: case SCANK: case SCAN0: case REV: case REV0: case REVK: case ASGN: case INDEX: case ELID: case IPROD: case OPROD: case IMMED: case HPRINT: case PRINT: case MIOT: case MIBM: case DIBM: case BRAN0: case BRAN: case FUN: case ARG1: case ARG2: case AUTO: case REST: case QRUN: case QEXEC: case FDEF: case QFORK: case QEXIT: case QWAIT: case QREAD: case QWRITE: case QUNLNK: case QRD: case QDUP: case QAP: case QKILL: case QSEEK: case QOPEN: case QCREAT: case QCLOSE: case QCHDIR: case QPIPE: case QCRP: case MFMT: case DFMT: case QNC: case NILRET:  pcp = s; (*exop[i])(); s = pcp; goto loop; case NAME: s =+ copy(IN, s, sp, 1); sp++; goto loop; case QUOT: j = CH; goto con; case CONST: j = DA; con: i = *s++; p = newdat(j, i==1?0:1, i); s =+ copy(j, s, p->datap, i); *sp++ = p; goto loop; case QUAD: *sp++ = newdat(QD, 0, 0); goto loop; case QQUAD: *sp++ = newdat(QQ, 0, 0); goto loop; case CQUAD: *sp++ = newdat(QC, 0, 0); goto loop; case PSI1: p = fetch1(); if (p->size != 0){ pop(); goto loop; } else s = psiskp (s); goto loop; case ISP1: p = fetch1(); if (p->size == 0){ pop(); goto loop; } else s = psiskp (s); goto loop; case PSI2: case ISP2: goto loop; } } psiskp (s) char *s; { register i; register struct item *p; register cnt; pop(); cnt = 1; psilp: i = *s++; switch (i){ default: goto psilp; case NAME: s =+ copy(IN,s,sp,1); sp++; pop(); goto psilp; case QUOT: i = *s++; s =+ i; goto psilp; case CONST: i = *s++; s =+ i * SDAT; goto psilp; case PSI1: case ISP1: cnt++; goto psilp; case PSI2: case ISP2: if((--cnt) == 0) { *sp++ = newdat (DA, 1, 0); return (s); } goto psilp; } } ex_dscal(m, f, p1, p2) int (*f)(); struct item *p1, *p2; { if(p1->type != p2->type) error("dyadic C"); if(p1->type == CH ) if(m) ex_cdyad(f, p1, p2); else error("dyadic T"); else ex_ddyad(f, p1, p2); } ex_ddyad(f, ap, ap1) data (*f)(); struct item *ap, *ap1; { register i; register struct item *p; register data *dp; struct item *p1; data d; p = ap; p1 = ap1; if(p->rank == 0 || p->size == 1) { d = p->datap[0]; pop(); p = p1; dp = p->datap; for(i=0; isize; i++) { *dp = (*f)(d, *dp); dp++; } return; } if(p1->rank == 0 || p1->size == 1) { sp--; d = p1->datap[0]; pop(); *sp++ = p; dp = p->datap; for(i=0; isize; i++) { *dp = (*f)(*dp, d); dp++; } return; } if(p1->rank != p->rank) error("dyadic C"); for(i=0; irank; i++) if(p->dim[i] != p1->dim[i]) error("dyadic C"); dp = p1->datap; for(i=0; isize; i++) { *dp = (*f)(p->datap[i], *dp); dp++; } pop(); } ex_cdyad(f, ap, ap1) data (*f)(); struct item *ap, *ap1; { register i; register struct item *p; register char *cp; struct item *p1; data d1, d2; p = ap; p1 = ap1; if(p->rank == 0 || p->size == 1) { d1 = p->datap->c[0]; pop(); p = p1; cp = p->datap; for(i=0; isize; i++) { d2 = *cp; *cp = (*f)(d1, d2); cp++; } } else if(p1->rank == 0 || p1->size == 1) { sp--; d1 = p1->datap->c[0]; pop(); *sp++ = p; cp = p->datap; for(i=0; isize; i++) { d2 = *cp; *cp = (*f)(d2, d1); cp++; } } else { if(p1->rank != p->rank) error("dyadic C"); for(i=0; irank; i++) if(p->dim[i] != p1->dim[i]) error("dyadic C"); cp = p1->datap; for(i=0; isize; i++) { d1 = p->datap->c[i]; d2 = *cp; *cp = (*f)(d1, d2); cp++; } p = p1; pop(); } /* * now convert the character vector to * a numeric array. Someday, we can make this a * call to whomever creates "logical" type data. */ p1 = p; cp = p->datap; p = newdat(DA, p->rank, p->size); for(i=0; irank; i++) p->dim[i] = p1->dim[i]; for(i=0; isize; i++) p->datap[i] = (*cp++) & 0377; pop(); *sp++ = p; } int (*exop[])() { 0, /* 0 */ &ex_add, /* 1 */ &ex_plus, /* 2 */ &ex_sub, /* 3 */ &ex_minus, /* 4 */ &ex_mul, /* 5 */ &ex_sgn, /* 6 */ &ex_div, /* 7 */ &ex_recip, /* 8 */ &ex_mod, /* 9 */ &ex_abs, /* 10 */ &ex_min, /* 11 */ &ex_floor, /* 12 */ &ex_max, /* 13 */ &ex_ceil, /* 14 */ &ex_pwr, /* 15 */ &ex_exp, /* 16 */ &ex_log, /* 17 */ &ex_loge, /* 18 */ &ex_cir, /* 19 */ &ex_pi, /* 20 */ &ex_comb, /* 21 */ &ex_fac, /* 22 */ &ex_deal, /* 23 */ &ex_rand, /* 24 */ &ex_drho, /* 25 */ &ex_mrho, /* 26 */ &ex_diot, /* 27 */ &ex_miot, /* 28 */ &ex_rot0, /* 29 */ &ex_rev0, /* 30 */ &ex_dtrn, /* 31 */ &ex_mtrn, /* 32 */ &ex_dibm, /* 33 */ &ex_mibm, /* 34 */ &ex_gdu, /* 35 */ &ex_gduk, /* 36 */ &ex_gdd, /* 37 */ &ex_gddk, /* 38 */ &ex_exd, /* 39 */ &ex_scan, /* 40 */ &ex_exdk, /* 41 */ &ex_scnk, /* 42 */ &ex_iprod, /* 43 */ &ex_oprod, /* 44 */ 0, /* 45 */ 0, /* 46 */ &ex_br0, /* 47 */ &ex_br, /* 48 */ &ex_ddom, /* 49 */ &ex_mdom, /* 50 */ &ex_com, /* 51 */ &ex_red, /* 52 */ &ex_comk, /* 53 */ &ex_redk, /* 54 */ &ex_rot, /* 55 */ &ex_rev, /* 56 */ &ex_rotk, /* 57 */ &ex_revk, /* 58 */ &ex_cat, /* 59 */ &ex_rav, /* 60 */ &ex_catk, /* 61 */ &ex_ravk, /* 62 */ &ex_print, /* 63 */ 0, /* 64 */ &ex_elid, /* 65 */ 0, /* 66 */ 0, /* 67 */ &ex_index, /* 68 */ &ex_hprint, /* 69 */ 0, /* 70 */ &ex_lt, /* 71 */ &ex_le, /* 72 */ &ex_gt, /* 73 */ &ex_ge, /* 74 */ &ex_eq, /* 75 */ &ex_ne, /* 76 */ &ex_and, /* 77 */ &ex_or, /* 78 */ &ex_nand, /* 79 */ &ex_nor, /* 80 */ &ex_not, /* 81 */ &ex_eps, /* 82 */ &ex_meps, /* 83 */ &ex_rep, /* 84 */ &ex_take, /* 85 */ &ex_drop, /* 86 */ &ex_exd0, /* 87 */ &ex_asgn, /* 88 */ &ex_immed, /* 89 */ 0, /* 90 */ 0, /* 91 */ &ex_fun, /* 92 */ &ex_arg1, /* 93 */ &ex_arg2, /* 94 */ &ex_auto, /* 95 */ &ex_rest, /* 96 */ &ex_com0, /* 97 */ &ex_red0, /* 98 */ &ex_exd0, /* 99 */ &ex_scn0, /*100 */ &ex_base, /*101 */ &ex_menc, /*102 */ /* monadic encod */ 0, /*103 */ 0, /*104 */ 0, /*105 */ 0, /*106 */ 0, /*107 */ 0, /*108 */ 0, /*109 */ 0, /*110 */ 0, /*111 */ &ex_run, /*112 */ &ex_fork, /*113 */ &ex_wait, /*114 */ &ex_exec, /*115 */ &ex_fdef, /*116 */ &ex_exit, /*117 */ &ex_pipe, /*118 */ &ex_chdir, /*119 */ &ex_open, /*120 */ &ex_close, /*121 */ &ex_read, /*122 */ &ex_write, /*123 */ &ex_creat, /*124 */ &ex_seek, /*125 */ &ex_unlink, /*126 */ &ex_rd, /*127 */ &ex_dup, /*128 */ &ex_ap, /*129 */ &ex_kill, /*130 */ &ex_crp, /*131 */ &ex_dfmt, /*132 */ &ex_mfmt, /*133 */ &ex_nc, /*134 */ &ex_nilret, /*135 */ &ex_botch, /*136 */ }; ex_botch() { error("exec P E"); } q/q 4/purdue/src/apl/a2.c#include "apl.h" ex_print() { if(epr0()) putchar('\n'); } ex_hprint() { epr0(); pop(); } epr0() { register struct item *p; register data *dp; register i; int j; int param[4]; p = fetch1(); if(p->type == DU) return(0); if(p->size == 0) return(1); if(p->type == DA) { for(i=0; i<4; i++) param[i] = 0; dp = p->datap; for(i=0; isize; i++) epr1(*dp++, param); i = param[1] + param[2]; /* size if fp */ if(i > thread.digits) i =+ 100; if(param[2]) i++; if(i > param[0]+5) { i = param[0] + 5; /* size if ep */ param[1] = param[0]; param[2] = -1; } if(param[3]) i++; /* sign */ i++; /* leading space */ param[0] = i; dp = p->datap; } bidx(p); for(i=1; isize; i++) { if(intflg) break; if(p->type == CH) { j = getdat(p); putchar(j); } else epr2(*dp++, param); for(j=p->rank-2; j>=0; j--) if(i%idx.del[j] == 0) putchar('\n'); } if(p->type == CH) { j = getdat(p); putchar(j); } else epr2(*dp, param); return(1); } epr1(d, param) data d; int *param; { double f; register a; register char *c; int dp, sg; f = d; c = ecvt(f, thread.digits, &dp, &sg); a = thread.digits; while(c[a-1]=='0' && a>1) a--; if(a > param[0]) /* sig digits */ param[0] = a; a =- dp; if(a < 0) a = 0; if(a > param[2]) /* digits to right of dp */ param[2] = a; if(dp > param[1]) /* digits to left of dp */ param[1] = dp; param[3] =| sg; /* and sign */ } epr2(d, param) int *param; data d; { register i; register char *c, *mc; double f; int dp, sg; if(param[0]+column > thread.width) { putchar('\n'); putto(param[0]); } f = d; c = ecvt(f, thread.digits, &dp, &sg); mc = c + thread.digits; putchar(' '); sg = sg? '-': ' '; /* '-' used to be '"' */ if(param[2] < 0) { if(param[3]) putchar(sg); for(i=0; i= mc) putchar('0'); else putchar(*c++); for(i=0; i= mc) putchar('0'); else putchar(*c++); } } 'q.q4/purdue/src/apl/a3.c#include "apl.h" ex_miot() { register struct item *p; register data *dp; register i; i = topfix(); if(i < 0) error("miot D"); p = newdat(DA, 1, i); dp = p->datap; datum = thread.iorg; for(; i; i--) { *dp++ = datum; datum =+ one; } *sp++ = p; } ex_mrho() { register struct item *p, *q; register data *dp; int i; p = fetch1(); q = newdat(DA, 1, p->rank); dp = q->datap; for(i=0; irank; i++) *dp++ = p->dim[i]; pop(); *sp++ = q; } ex_drho() { register struct item *p, *q; struct item *r; int s, i; register data *dp; char *cp; p = fetch2(); q = sp[-2]; if(p->type != DA || p->rank > 1 || q->size < 1) error("rho C"); s = 1; dp = p->datap; for(i=0; isize; i++) s =* fix(*dp++); r = newdat(q->type, p->size, s); dp = p->datap; for(i=0; isize; i++) r->dim[i] = fix(*dp++); cp = r->datap; while(s > 0) { i = s; if(i > q->size) i = q->size; cp =+ copy(q->type, q->datap, cp, i); s =- i; } pop(); pop(); *sp++ = r; } eq-q4/purdue/src/apl/a4.c#include "apl.h" ex_asgn() { register struct nlist *p; register struct item *q; p = sp[-1]; if(p->type == QD) { pop(); ex_print(); return; } if(p->type == QC) { pop(); ex_plot(); return; } if(p->type == QQ){ pop(); epr0(); /* print w/out '\n' (in a2.c) */ return; } if(p->type != LV) error("asgn lv"); if(p->use != 0 && p->use != DA) error("asgn var"); sp--; q = fetch1(); erase(p); p->use = DA; p->itemp = q; sp[-1] = p; } ex_elid() { *sp++ = newdat(EL, 0, 0); } ex_index() { register struct item *p; struct item *q; register i, j; int f, n, lv; n = *pcp++; f = *pcp; p = sp[-1]; if(f == ASGN) { pcp++; if(p->type != LV) error("indexed assign value"); if(p->use != DA) fetch1(); /* error("used before set"); */ q = p->itemp; } else q = fetch1(); if(q->rank != n) error("subscript C"); idx.rank = 0; for(i=0; itype == EL) { idx.dim[idx.rank++] = q->dim[i]; continue; } p = fetch(p); sp[-i-2] = p; for(j=0; jrank; j++) idx.dim[idx.rank++] = p->dim[j]; } size(); if(f == ASGN) { p = fetch(sp[-n-2]); sp[-n-2] = p; if(p->size > 1) { if(idx.size != p->size) error("assign C"); f = 1; /* v[i] <- v */ } else { datum = getdat(p); f = 2; /* v[i] <- s */ } ex_elid(); } else { p = newdat(q->type, idx.rank, idx.size); copy(IN, idx.dim, p->dim, idx.rank); *sp++ = p; f = 0; /* v[i] */ } bidx(q); index1(0, f); if(f == 0) { p = sp[-1]; sp--; for(i=0; i<=n; i++) pop(); *sp++ = p; } else { sp =- 2; for(i=0; i= idx.rank) switch(f) { case 0: p = sp[-2]; p->index = access(); putdat(sp[-1], getdat(p)); return; case 1: datum = getdat(sp[-idx.rank-3]); case 2: p = sp[-2]->itemp; p->index = access(); putdat(p, datum); return; } p = sp[-i-3]; if(p->type == EL) { for(j=0; jindex = 0; for(j=0; jsize; j++) { k = fix(getdat(p)) - thread.iorg; if(k < 0 || k > idx.dim[i]) error("subscript X"); idx.idx[i] = k; index1(i+1, f); } } q,⏗q4/purdue/src/apl/a5.c#include "apl.h" ex_rav() { register struct item *p, *r; p = fetch1(); if(p->rank == 0) { r = newdat(p->type, 1, 1); putdat(r, getdat(p)); pop(); *sp++ = r; return; } rav0(p->rank-1); } ex_ravk() { register i; i = topfix() - thread.iorg; fetch1(); rav0(i); } rav0(k) { register struct item *p, *r; struct item *param[2]; int rav1(); p = sp[-1]; bidx(p); colapse(k); r = newdat(p->type, 1, p->size); param[0] = p; param[1] = r; forloop(rav1, param); pop(); *sp++ = r; } rav1(param) struct item *param[]; { register struct item *p; register i, n; p = param[0]; n = access(); for(i=0; iindex = n; putdat(param[1], getdat(p)); n =+ idx.delk; } } ex_cat() { register struct item *p, *q; struct item *r; register k; p = fetch2(); q = sp[-2]; k = p->rank; if(q->rank > k) k = q->rank; if(k == 0) { r = newdat(p->type, 1, 2); putdat(r, getdat(p)); putdat(r, getdat(q)); pop(); pop(); *sp++ = r; } else cat0(k-1); } ex_catk() { register k; k = topfix() - thread.iorg; fetch2(); cat0(k); } cat0(k) { register struct item *p, *q; register i; struct item *r; int a, b; p = sp[-1]; q = sp[-2]; i = k; if(p->rank >= q->rank) { bidx(p); b = cat1(q, i); a = idx.dim[i]; } else { bidx(q); a = cat1(p, i); b = idx.dim[i]; } idx.dim[i] = a+b; size(); r = newdat(p->type, idx.rank, idx.size); copy(IN, idx.dim, r->dim, idx.rank); i = idx.del[i]; a =* i; b =* i; while(r->index < r->size) { for(i=0; i= idx.rank) error("cat X"); p = ip; a = 1; if(p->rank == 0) return(a); j = 0; for(i=0; irank == idx.rank) { a = p->dim[i]; j++; } continue; } if(idx.dim[i] != p->dim[j]) error("cat C"); j++; } return(a); } q+돗q4/purdue/src/apl/a6.c#include "apl.h" ex_red0() { fetch1(); red0(0); } ex_red() { register struct item *p; p = fetch1(); red0(p->rank-1); } ex_redk() { register i; i = topfix() - thread.iorg; fetch1(); red0(i); } red0(k) { register struct item *p, *q; int param[3], red1(); p = fetch1(); if(p->type != DA) error("red T"); bidx(p); colapse(k); if(idx.dimk == 0) { /* * reduction identities - ets/jrl 5/76 */ q = newdat(DA,0,1); q->dim[0] = 1; switch(*pcp++) { case ADD: case SUB: case OR: q->datap[0] = 0; break; case AND: case MUL: case DIV: q->datap[0] = 1; break; case MIN: q->datap[0] = 1.0e38; break; case MAX: q->datap[0] = -1.0e38; break; default: error("reduce identity"); } pop(); *sp++ = q; return; } q = newdat(idx.type, idx.rank, idx.size); copy(IN, idx.dim, q->dim, idx.rank); param[0] = p->datap; param[1] = q; param[2] = exop[*pcp++]; forloop(red1, param); pop(); *sp++ = q; } red1(param) int param[]; { register i; register data *dp; data d, (*f)(); dp = param[0]; dp =+ access() + (idx.dimk-1) * idx.delk; f = param[2]; d = *dp; for(i=1; itype != DA || q->type != DA) error("iprod T"); bidx(p); idx.rank--; param[2] = idx.dim[idx.rank]; if(param[2] != q->dim[0]) error("inner prod C"); param[3] = q->size/param[2]; for(i=1; irank; i++) idx.dim[idx.rank++] = q->dim[i]; r = newdat(DA, idx.rank, size()); copy(IN, idx.dim, r->dim, idx.rank); param[4] = 0; param[5] = 0; param[6] = p->datap; param[7] = q->datap; param[8] = r->datap; param[9] = p->size; forloop(ipr1, param); pop(); pop(); *sp++ = r; } ipr1(param) int param[]; { register i, dk; int lk, a, b; data *dp1, *dp2, *dp3; data (*f1)(), (*f2)(), d; f1 = param[0]; f2 = param[1]; dk = param[2]; lk = param[3]; a = param[4]; b = param[5]; dp1 = param[6]; dp2 = param[7]; dp3 = param[8]; a =+ dk; b =+ (dk * lk); for(i=0; i= lk) { param[5] = 0; param[4] =+ dk; if(param[4] >= param[9]) param[4] = 0; } } ex_oprod() { register i, j; register data *dp; struct item *p, *q, *r; data *dp1, *dp2; data (*f)(); f = exop[*pcp++]; p = fetch2(); q = sp[-2]; if(p->type != DA || q->type != DA) error("oprod T"); bidx(p); for(i=0; irank; i++) idx.dim[idx.rank++] = q->dim[i]; r = newdat(DA, idx.rank, size()); copy(IN, idx.dim, r->dim, idx.rank); dp = r->datap; dp1 = p->datap; for(i=0; isize; i++) { datum = *dp1++; dp2 = q->datap; for(j=0; jsize; j++) *dp++ = (*f)(datum, *dp2++); } pop(); pop(); *sp++ = r; } q)q<4/purdue/src/apl/a8.c#include "apl.h" ex_mdom() { register data *dp; register a; int i, j; struct item *p, *q; p = fetch1(); if(p->rank != 2) error("mdom C"); a = p->dim[0]; q = newdat(DA, 2, a*a); q->dim[0] = a; q->dim[1] = a; *sp++ = q; dp = q->datap; for(i=0; itype != DA || q->type != DA) error("domino T"); if((p->rank != 1 && p->rank != 2) || q->rank != 2) error("domino C"); m = q->dim[0]; n = q->dim[1]; if(m < n || m != p->dim[0]) error("domino R"); o = 1; if(p->rank == 2) o = p->dim[1]; a = alloc(n*(SINT + SDAT*m + SDAT*3) + SDAT*m); if(a == -1) error("domino M"); dmn = a; dn1 = dmn + m*n; dn2 = dn1 + n; dn3 = dn2 + n; dm = dn3 + n; in = dm + m; d1 = q->datap; for(b=0; bdatap, q->datap); free(dmn); if(a) error("domino D"); sp--; pop(); *sp++ = p; p->dim[0] = n; p->size = n*o; } lsq(dmn, dn1, dn2, dn3, dm, in, m, n, p, d1, d2) data *dmn, *dn1, *dn2, *dn3, *dm; data *d1, *d2; int *in; { register data *dp1, *dp2; double f1, f2, f3, f4; int i, j, k, l; dp1 = dmn; dp2 = dn1; for(j=0; j= 0.) f2 = -f2; dn2[k] = f2; f1 = 1./(f1 - f3*f2); dmn[k*m+k] = f3 - f2; for(j=k+1; j 0.0625*f4) return(1); loop: if(intflg) return(1); dp1 = dn3; dp2 = dn1; for(i=0; i=0; i--) { f1 = -*--dp1; k = (i+1)*m + i; for(j=i+1; jdatap[0] = datum; *sp++ = p; } q'q^4/purdue/src/apl/aa.c#include "apl.h" int gdu(); int gdd(); ex_gdu() { register struct item *p; p = fetch1(); gd0(p->rank-1, gdu); } ex_gduk() { register k; k = topfix() - thread.iorg; fetch1(); gd0(k, gdu); } ex_gdd() { register struct item *p; p = fetch1(); gd0(p->rank-1, gdd); } ex_gddk() { register k; k = topfix() - thread.iorg; fetch1(); gd0(k, gdd); } gd0(k, f) int (*f)(); { register struct item *p; int param[2]; int gd1(); bidx(sp[-1]); if(k < 0 || k >= idx.rank) error("grade X"); p = newdat(DA, idx.rank, idx.size); copy(IN, idx.dim, p->dim, idx.rank); *sp++ = p; colapse(k); param[0] = alloc(idx.dimk*SINT); param[1] = f; forloop(gd1, param); free(param[0]); p = sp[-1]; sp--; pop(); *sp++ = p; } gd1(param) int param[]; { register struct item *p; register i, *m; integ = access(); m = param[0]; for(i=0; iindex = integ; datum = *m++ + thread.iorg; putdat(p, datum); integ =+ idx.delk; } } gdu(p1, p2) int *p1, *p2; { register struct item *p; data d1, d2; p = sp[-2]; p->index = integ + *p1 * idx.delk; d1 = getdat(p); p->index = integ + *p2 * idx.delk; d2 = getdat(p); if(fuzz(d1, d2) != 0) { if(d1 > d2) return(1); return(-1); } return(*p1 - *p2); } gdd(p1, p2) int *p1, *p2; { register struct item *p; data d1, d2; p = sp[-2]; p->index = integ + *p1 * idx.delk; d1 = getdat(p); p->index = integ + *p2 * idx.delk; d2 = getdat(p); if(fuzz(d1, d2) != 0) { if(d1 > d2) return(-1); return(1); } return(*p1 - *p2); } q&q 4/purdue/src/apl/ab.c#include "apl.h" ex_take() { register i, k, o; o = 0; td1(); for(i=0; i 0) o =+ idx.del[i] * k; else k = -k; idx.dim[i] =- k; } map(o); } td1() { register struct item *p; struct item *q; register i, k; p = fetch2(); q = sp[-2]; if(q->rank == 0) /* scalar to 1 element vector */ q = s2vect(q); if(p->rank > 1 || q->rank != p->size) error("take/drop C"); bidx(q); for(i=0; isize; i++) { k = fix(getdat(p)); idx.idx[i] = k; if(k < 0) k = -k; if(k > idx.dim[i]) error("take/drop C"); } pop(); } ex_dtrn() { register struct item *p, *q; register i; p = fetch2(); q = sp[-2]; if(p->rank > 1 || p->size != q->rank) error("tranpose C"); for(i=0; isize; i++) idx.idx[i] = fix(getdat(p)) - thread.iorg; pop(); trn0(); } ex_mtrn() { register struct item *p; register i; p = fetch1(); if(p->rank <= 1) return; for(i=0; irank; i++) idx.idx[i] = i; idx.idx[i-1] = i-2; idx.idx[i-2] = i-1; trn0(); } trn0() { register i, j; int d[MRANK], r[MRANK]; bidx(sp[-1]); for(i=0; i=idx.rank) error("tranpose X"); if(d[j] != -1) { if(idx.dim[i] < d[j]) d[j] = idx.dim[i]; r[j] =+ idx.del[i]; } else { d[j] = idx.dim[i]; r[j] = idx.del[i]; } } j = idx.rank; for(i=0; i j) error("tranpose D"); idx.dim[i] = d[i]; idx.del[i] = r[i]; } else if(i < j) j = i; } idx.rank = j; map(0); } ex_rev0() { fetch1(); revk(0); } ex_revk() { register k; k = topfix() - thread.iorg; fetch1(); revk(k); } ex_rev() { register struct item *p; p = fetch1(); revk(p->rank-1); } revk(k) { register o; bidx(sp[-1]); if(k < 0 || k >= idx.rank) error("reverse X"); o = idx.del[k] * (idx.dim[k]-1); idx.del[k] = -idx.del[k]; map(o); } map(o) { register struct item *p; register n, i; int map1(); n = 1; for(i=0; idim, idx.rank); *sp++ = p; if(n != 0) forloop(map1, o); sp--; pop(); *sp++ = p; } map1(o) { register struct item *p; p = sp[-2]; p->index = access() + o; putdat(sp[-1], getdat(p)); } kq%q4/purdue/src/apl/ac.c#include "apl.h" ex_rot0() { fetch2(); rotk(0); } ex_rotk() { register k; k = topfix() - thread.iorg; fetch2(); rotk(k); } ex_rot() { register struct item *p; fetch2(); p = sp[-2]; rotk(p->rank-1); } rotk(k) { register struct item *p, *q; register param; int rot1(); p = sp[-1]; bidx(sp[-2]); if(k < 0 || k >= idx.rank) error("rotate X"); param = 0; colapse(k); if(idx.size != p->size) { if(p->size != 1) error("rotate C"); param++; datum = getdat(p); } p = newdat(idx.type, 1, idx.dimk); *sp++ = p; forloop(rot1, param); pop(); pop(); } rot1(param) { register struct item *p, *q; register i; int o, n; if(param == 0) datum = getdat(sp[-2]); o = fix(datum); if(o < 0) o = idx.dimk - (-o % idx.dimk); q = sp[-1]; p = sp[-3]; q->index = 0; n = access(); for(i=0; iindex = n + (o%idx.dimk)*idx.delk; putdat(q, getdat(p)); o++; } for(i=0; iindex = n; putdat(p, getdat(q)); n =+ idx.delk; } } q$qI4/purdue/src/apl/ad.c#include "apl.h" ex_com0() { fetch2(); comk(0); } ex_comk() { register k; k = topfix() - thread.iorg; fetch2(); comk(k); } ex_com() { register struct item *q; fetch2(); q = sp[-2]; comk(q->rank-1); } comk(k) { register struct item *p; data d; register i; int dk, ndk, com1(); p = sp[-1]; bidx(sp[-2]); if(p->rank == 0) { if(getdat(p)) { pop(); return; } p = newdat(idx.type, 1, 0); pop(); pop(); *sp++ = p; return; } if(idx.rank == 0 && p->rank == 1) { /* then scalar right arg ok */ dk = p->dim[0]; ndk = 0; for (i=0; i= idx.rank) error("compress X"); dk = idx.dim[k]; if(p->rank != 1 || p->size != dk) error("compress C"); ndk = 0; for(i=0; idim, idx.rank); p->dim[k] = ndk; *sp++ = p; forloop(com1, k); sp--; pop(); pop(); *sp++ = p; } com1(k) { register struct item *p; p = sp[-2]; p->index = idx.idx[k]; if(getdat(p)) { p = sp[-3]; p->index = access(); putdat(sp[-1], getdat(p)); } } ex_exd0() { fetch2(); exdk(0); } ex_exdk() { register k; k = topfix() - thread.iorg; fetch2(); exdk(k); } ex_exd() { register struct item *q; fetch2(); q = sp[-2]; exdk(q->rank-1); } exdk(k) { register struct item *p; register i, dk; int exd1(); p = sp[-1]; bidx(sp[-2]); if(k < 0 || k >= idx.rank) error("expand X"); dk = 0; for(i=0; isize; i++) if(getdat(p)) dk++; if(p->rank != 1 || dk != idx.dim[k]) error("expand C"); idx.dim[k] = p->size; size(); p = newdat(idx.type, idx.rank, idx.size); copy(IN, idx.dim, p->dim, idx.rank); *sp++ = p; forloop(exd1, k); sp--; pop(); pop(); *sp++ = p; } exd1(k) { register struct item *p; p = sp[-2]; p->index = idx.idx[k]; if(getdat(p)) datum = getdat(sp[-3]); else if(idx.type == DA) datum = zero; else datum = ' '; putdat(sp[-1], datum); } aq"q{4/purdue/src/apl/ae.c#include "apl.h" ex_base() { register struct item *p, *q; int s, s1; data d, d1; double r, b; p = fetch2(); q = sp[-2]; if(p->rank > 1 || q->rank > 1) error("base R"); b = 1.; r = 0.; s = p->size; s1 = q->size; while(s > 0 || s1 > 0) { if(s > 0) { s--; p->index = s; d = getdat(p); } if(s1 > 0) { s1--; q->index = s1; d1 = getdat(q); } r =+ d1 * b; b =* d; } pop(); pop(); p = newdat(DA, 0, 1); *sp++ = p; d = r; putdat(p, d); } ex_rep() { register struct item *p, *q; register s; double a, b, r; p = fetch2(); q = sp[-2]; if(q->size != 1 || p->rank > 1) error("represent R"); r = getdat(q); s = p->size; while(s > 0) { s--; p->index = s; b = getdat(p); if(b == 0.) error("represent D"); r =/ b; a = r; r = floor(r); datum = (a - r) * b; p->index = s; putdat(p, datum); } sp--; pop(); *sp++ = p; } q!qB4/purdue/src/apl/af.c"iobmted!"`ql.h" dy^edam(( z sdgisuds rurtcu hudm!*p: sdgisuds l- n: enucld!f: e`u`!d0- d2: m! n(  esrns("ddam D"(; q 0(!z  g index = m; putdat(p, d1); } } *sp++ = p; } q q 4/purdue/src/apl/ag.c"iobmted!"`ql.h" dy^ehou(( z sdgisuds rurtcu hudm!*p, *p- *r: iot h- j: q 0) close(protofile); protofile = 0; return; } if((protofile = open(cp, 1)) > 0){ seek(protofile, 0, 2); } else { if((protofile = creat(cp, 0644)) < 0){ printf("can't create %s\n", cp); protofile = 0; } } write(protofile, "\t)script on\n", 12); return; case DEBUG: debug = ~debug; return; case DIGITS: i = topfix(); if(i < 1 || i > 20) error("digits D"); printf("was %d\n",thread.digits); thread.digits = i; return; case EDIT: funedit(); return; case FUZZ: i = topfix(); if(i <= 0) { thread.fuzz = 0.; return; } f = i; thread.fuzz = exp(-f*2.3025851); return; case ORIGIN: printf("was %d\n",thread.iorg); thread.iorg = topfix(); return; case WIDTH: i = topfix(); if(i < 1) error("width D"); printf("was %d\n",thread.width); thread.width = i; return; case READ: funload(0); return; case ERASE: p = sp[-1]; sp--; erase(p); return; case CONTIN: if((i=creat("continue",0644)) < 0) error("cannot create"); wssave(i); printf(" continue"); case OFF: term(); case VARS: for(n=nlist; n->namep; n++) if(n->itemp && n->use == DA) { if(column+8 >= thread.width) printf("\n\t"); printf(n->namep); putchar('\t'); } putchar('\n'); return; case FNS: for(n=nlist; n->namep; n++) if(n->use == DF || n->use == MF || n->use == NF) { if(column+8 >= thread.width) printf("\n\t"); printf(n->namep); putchar('\t'); } putchar('\n'); return; case CLEAR: clear(); printf("clear ws\n"); break; case LIB: listdir(); return; case LOAD: funload(2); break; case COPY: funload(1); return; case DROPC: unlink(vfname()); return; case SAVE: if((i=creat(vfname(), 0644)) < 0) error("cannot creat"); wssave(i); putchar('\n'); return; case VSAVE: if((i=creat(vfname(), 0644)) < 0) error("cannot creat"); vsave(i); putchar('\n'); return; } /* special return for after clear */ sp = stack; reset(); } vfname() { register struct nlist *n; n = sp[-1]; sp--; if(n->type != LV) error("save B"); return(n->namep); } q˖qB4/purdue/src/apl/ai.c#include "apl.h" funedit() { register struct item *p; register f, a; p = sp[-1]; if(p->type != LV) error("fed B"); f = fork(); if(f == 0) { for(f=3; f<7; f++) close(f); f = "/usr/bin/ned"; execl(f+4, f+9, p->namep, "-a", 0); execl(f, f+9, p->namep, "-a", 0); printf("cannot find the editor!\n"); exit(); } if(f == -1) error("try again"); a = signal(2, 1); while(wait0() != f) ; signal(2, a); funload(0); } funload(s) { register struct item *p; register f, pid; p = sp[-1]; sp--; if(p->type != LV) error("fnl B"); if(s == 0){ if((pid = fork()) == 0){ execl("/usr/bin/aplp", "aplp", p->namep, LPFILE, 0); printf("can't exec label processor\n"); exit(3); } if(pid == -1) error("can't fork label processor\n"); f = signal(2,1); while(wait0() != pid) {} signal(2,f); f = open(LPFILE, 0); } else f = open(p->namep, 0); if(f <= 0) error("cannot open"); switch(s) { case 0: fundef(f); return; case 2: clear(); case 1: wsload(f); putchar('\n'); } } fundef(f) { register a, c; struct nlist *np; int b[256]; ifile = f; a = rline(0); if(a == 0) error("fnd eof"); c = compile(a, 2); free(a); if(c == 0) goto out; copy(IN, c+1, &np, 1); erase(np); np->use = c->c[0]; fstat(wfile, b); np->label = b[5]; seek(wfile, b[5], 0); seek(ifile, 0, 0); while((a=read(ifile, b, 512)) > 0) write(wfile, b, a); write(wfile, "", 1); out: close(ifile); ifile = 0; } funcomp(np) struct nlist *np; { register a, c, *p; int err, size; ifile = dup(wfile); seek(ifile, np->label, 0); size = 0; err = 0; pass1: a = rline(0); if(a == 0) { if(err) goto out; p = alloc((size+2)*SINT); *p = size; size = 0; seek(ifile, np->label, 0); err++; goto pass2; } c = compile(a, size==0? 3: 5); size++; free(a); if(c == 0) { err++; goto pass1; } free(c); goto pass1; pass2: a = rline(0); if(a == 0) goto pass3; c = compile(a, size==0? 3: 5); size++; free(a); if(c == 0) goto out; p[size] = c; goto pass2; pass3: seek(ifile, np->label, 0); a = rline(0); if(a == 0) goto out; c = compile(a, 4); free(a); if(c == 0) goto out; p[size+1] = c; if(debug) { dump(p[1]); dump(c); } np->itemp = p; err = 0; out: close(ifile); ifile = 0; if(err) error("syntax"); } ex_fun() { struct nlist *np; register *p, s; int oldflc, oldpcp, oldib36; pcp =+ copy(IN, pcp, &np, 1); if(np->itemp == 0) funcomp(np); p = np->itemp; oldflc = funlc; oldib36 = ibeam36; ibeam36 = funlc; oldpcp = pcp; funlc = 0; s = *p; loop: funlc++; execute(p[funlc]); if(intflg) error("I"); if(funlc <= 0 || funlc >= s) { execute(p[s+1]); funlc = oldflc; pcp = oldpcp; ibeam36 = oldib36; return; } pop(); goto loop; } ex_arg1() { register struct item *p; struct nlist *np; pcp =+ copy(IN, pcp, &np, 1); p = fetch1(); sp[-1] = np->itemp; np->itemp = p; np->use = DA; } ex_arg2() { register struct item *p1, *p2; struct nlist *np1, *np2; pcp =+ copy(IN, pcp, &np2, 1); /* get first argument's name */ pcp++; /* skip over ARG1 */ pcp =+ copy(IN, pcp, &np1, 1); /* get second arg's name */ p1 = fetch1(); /* get first expr to be bound to arg */ p2 = fetch(sp[-2]); /* get second one */ sp[-1] = np1->itemp; /* save old value of name on stack */ sp[-2] = np2->itemp; /* save second */ np1->itemp = p1; /* new arg1 binding */ np2->itemp = p2; /* ditto arg2 */ np1->use = DA; /* release safety catch */ np2->use = DA; } ex_auto() { struct nlist *np; pcp =+ copy(IN, pcp, &np, 1); *sp++ = np->itemp; np->itemp = 0; np->use = 0; } ex_rest() { register struct item *p; struct nlist *np; p = fetch1(); pcp =+ copy(IN, pcp, &np, 1); erase(np); np->itemp = sp[-2]; np->use = 0; if(np->itemp) np->use = DA; sp--; sp[-1] = p; } ex_br0() { funlc = 0; ex_elid(); } ex_br() { register struct item *p; p = fetch1(); if(p->size == 0) return; funlc = fix(getdat(p)); } ex_fdef() { register struct item *p; register char *p1, *p2; struct nlist *np; char b[512]; int i, dim0, dim1, sb[32]; p = fetch1(); if((p->rank != 2 && p->rank != 1) || p->type != CH) error("Lfx D"); dim0 = p->dim[0]; dim1 = p->dim[1]; if(p->rank == 1) dim1 = dim0; copy(CH, p->datap, b, dim1); b[dim1] = '\n'; p2 = compile(b, 2); if(p2 != 0){ copy(IN, p2+1, &np, 1); erase(np); np->use = *p2; free(p2); fstat(wfile, sb); np->label = sb[5]; seek(wfile,sb[5],0); fappend(wfile, p); write(wfile,"",1); } pop(); *sp++ = newdat(DA, 1, 0); } ex_nilret() { pop(); /* zap last result */ *sp++ = newdat(DU,0,0); /* put looser onto stack */ /* (should be discarded) */ } qݖq 4/purdue/src/apl/aj.c#include "apl.h" clear() { register struct nlist *n; extern freelist[], end; for(n=nlist; n->namep; n++) { n->itemp = n->use = 0; n->namep = 0; } freelist[0] = 0; freelist[1] = -1; /*empty free list*/ brk(&end); /*shrink core*/ } lsize(s) char *s; { register i; register char *p; i=1; p=s; while (*p++) i++; return(i); } isize(ip) struct item *ip; { register struct item *p; register i; p=ip; i=sizeof *p + p->rank*SINT; if(p->type == DA) i =+ p->size*SDAT; else if(p->type == CH) i =+ p->size; return(i); } wsload(ffile) { int b[18]; char name[NAMS]; int iz; register i; register struct nlist *n; register struct item *p; char c; struct { int word; }; iz = 0; /* Check for correct magic number */ read(ffile,&iz,2); if(iz != MAGIC) { barf: close(ffile); error("bad load format"); } read(ffile,&thread,sizeof thread); while(read(ffile,&iz,2) == 2) { i = iz.c[1]; /* read name of vbl or fn */ read(ffile,name,i); for(n=nlist; n->namep; n++) if(equal(name,n->namep)) { erase(n); goto hokay; } n->namep = alloc(i); copy(CH,name,n->namep,i); hokay: n->use = iz.c[0]; n->type = LV; switch(n->use) { default: goto barf; case DA: read(ffile,&iz,2); p=alloc(iz); read(ffile,p,iz); p->label =+ (&p)->word; /*make absolute*/ n->itemp = p; continue; case NF: case MF: case DF: n->itemp = 0; fstat(wfile,b); n->label=b[5]; seek(wfile,b[5],0); do { read(ffile,&c,1); write(wfile,&c,1); } while(c != 0); } } fdat(ffile); close(ffile); } wssave(ffile) { register struct nlist *n; nsave(ffile, 0); for(n=nlist; n->namep; n++) nsave(ffile, n); fdat(ffile); close(ffile); } vsave(fd) { register struct nlist *n; nsave(fd, 0); while(n = getnm()) nsave(fd, n); fdat(fd); close(fd); } nsave(ffile, an) struct nlist *an; { int iz; register struct nlist *n; register i; register struct item *p; char c; struct { int word; }; n = an; if(n == 0){ iz = MAGIC; write(ffile,&iz,2); write(ffile,&thread,sizeof thread); return(0); } if(n->use == 0 || (n->use == DA && n->itemp == 0)) return(0); iz.c[0] = n->use; iz.c[1] = i = lsize(n->namep); write(ffile,&iz,2); write(ffile,n->namep,i); switch(n->use) { default: close(ffile); error("save B"); case DA: p = n->itemp; iz = i = isize(p); p -> label =- (&p)->word; write(ffile,&iz,2); write(ffile,p,i); p->label =+ (&p)->word; break; case NF: case MF: case DF: seek(wfile,n->label,0); do { read(wfile,&c,1); write(ffile,&c,1); } while(c != 0); } return(0); } getnm() { char name[100]; register char *p; register struct nlist *n; register c; while(1){ printf("variable name? "); c = read(1, name, 100); if(c <= 1) return(0); name[c-1] = 0; for(n=nlist; n->namep; n++) if(equal(name, n->namep)) return(n); printf("%s does not exist\n", name); } } listdir() { register f; struct { int in; char nam[14]; } dir; if((f = open(".",0)) < 0) error("directory B"); while(read(f,&dir,sizeof dir) == sizeof dir) if(dir.in != 0 && dir.nam[0] != '.') { if(column+10 >= thread.width) printf("\n\t"); printf(dir.nam); putchar('\t'); } putchar('\n'); close(f); } fdat(f) { int b[18]; register *p; fstat(f,b); p = localtime(&b[16]); printf(" "); pr2d(p[2]); putchar('.'); pr2d(p[1]); putchar('.'); pr2d(p[0]); putchar(' '); pr2d(p[4]+1); putchar('/'); pr2d(p[3]); putchar('/'); pr2d(p[5]); } pr2d(i) { putchar(i/10+'0'); putchar(i % 10 + '0'); } q㖗q~4/purdue/src/apl/ak.c#include "apl.h" ex_scn0() { fetch1(); scan0(0); } ex_scan() { register struct item *p; p = fetch1(); scan0(p->rank-1); } ex_scnk() { register i; i = topfix() - thread.iorg; scan0(i); } scan0(k) { register struct item *p, *q; int param[2]; int scan1(); p = fetch1(); if(p->type != DA) error("scan T"); bidx(p); colapse(k); if(idx.dimk == 0) { /* * scan identities - ets/jrl 5/76 */ q = newdat(DA,0,1); q->dim[0] = 1; switch(*pcp++) { case ADD: case SUB: case OR: q->datap[0] = 0; break; case AND: case MUL: case DIV: q->datap[0] = 1; break; case MIN: q->datap[0] = 1.0e38; break; case MAX: q->datap[0] = -1.0e38; break; default: error("reduce identity"); } pop(); *sp++ = q; return; } param[0] = p->datap; param[1] = exop[*pcp++]; forloop(scan1, param); } scan1(param) int param[]; { register i; register data *dp; data d; data (*f)(); dp = param[0]; f = param[1]; dp =+ access(); d = *dp; for(i = 1; i < idx.dimk; i++) { dp =+ idx.delk; *dp = d = (*f)(*dp, d); } } data scalex 453.; data scaley 453.; data origx 0.0; data origy 0.0; ex_plot() { register struct item *p; register data *dp; register i; int ic; int x, y; p = fetch1(); if(p->type != DA) error("plot T"); if(p->rank != 2) error("plot R"); if(p->dim[1] != 2) error("plot C"); dp = p->datap; if ((i = p->dim[0]) == 0) return; ic=0; while(i--) { x = scalex*(*dp++ - origx); y = 454-(scaley*(*dp++ - origy)); if(x<0 || x >= 576 || y<0 || y>=454) error("plot off screen"); if(ic) line(x,y); else { move(x,y); ic=1; } } } line(x,y) { } move(x,y) { } qq4/purdue/src/apl/al.c# /* * monadic epsilon and encode /rww */ #include "apl.h" ex_meps() { struct item *p; register i,j; char *a,*b,*c; int dim0,dim1; int xpcp; p = fetch1(); if ( p->rank > 2 || p->type != CH ) error("execute C"); /*get out if nothing to do, apr 2-23-77 */ if (p->size == 0){ return; } b = p->datap; dim0 = p->rank < 2 ? 1 : p->dim[0]; dim1 = p->rank < 2 ? p->size : p->dim[1]; a = alloc ( dim1+1 ); xpcp = pcp; for ( i=0; itype == DA ) menc1(); /* else return (char argument unchanged); */ } ex_crp() /* dredge up a function and put it into an array*/ { char name[NAMS]; char *c, *c2; struct nlist *np; struct item *p; int len, dim0, dim1; register i; register char *dp; p = fetch1(); if ( p->size == 0 || p->rank >1 || p->size >= NAMS ) error("Lcr C"); /* set up the name in search format */ copy(CH, p->datap, name, p->size); name[p->size] = '\0'; np = nlook(name); /* if not found then domain error */ if ( !np->namep ) error("Lcr D"); switch(np->use){ default: error("Lcr D"); case MF: case DF: case NF: /* only allow functions */ ; } /* set up new array */ dim0 = 0; dim1 = 0; ifile = dup( wfile ); seek ( ifile, np->label, 0); /* look up function */ /* compute max width and height */ while ( c2 = c = rline(0) ){ while ( *c2++ != '\n' ){} dim0++; len = c2 - c - 1; dim1 = dim1 < len ? len : dim1; free(c); } pop(); /* release old variable */ /* create new array and put function in */ p = newdat ( CH, 2, dim0*dim1 ); p->rank = 2; p->dim[0] = dim0; p->dim[1] = dim1; dp = p->datap; seek ( ifile, np->label, 0); while ( c2 = c = rline(0) ){ for ( i=0; irank > 2) error("menc R"); dp = p->datap; /* find the maximum # of chars in any # */ for(i=0; isize; i++) epr1(*dp++, param); numsz = param[1] + param[2] + !!param[2] + param[3] + 1; /* rowsize is max # size x last dim */ rowsz = p->rank ? p->dim[p->rank-1] : 1; rowsz =* numsz; /* row size x # of rows (incl blank) */ total = p->size * numsz; for( j=i=0; irank; i++ ) if ( p->dim[i] != 1) if ( j++ > 1 ) total =+ rowsz; /* make new data and fill with blanks */ if(p->rank == 2){ q = newdat(CH, 2, total); q->dim[0] = total/rowsz; q->dim[1] = rowsz; } else { /* rank = 0 or 1 */ q = newdat( CH, 1, total); q->dim[0] = rowsz; } mencptr = q->datap; for ( i=0; idatap; /* use putchar() to fill up the array */ mencflg = 2; ex_hprint(); mencflg = 0; /* put it on the stack */ /* pop(); /* done by ex_hprint() */ *sp++ = q; } ex_run() { register struct item *p; register data *dp; register int *p2; char ebuf[100]; int i; p = fetch1(); if(p->type != CH || p->rank != 1) error("Lrun D"); copy(CH, p->datap, ebuf, p->size); ebuf[p->size] = 0; p2 = run(ebuf); p = newdat(DA, 1, 0); pop(); *sp++ = p; } int *run(s) char *s; { register p; static int a[3]; if(a[0]=fork()){ while((p = wait0(a+1)) != -1) if(p == a[0]) break; } else { execl("/bin/sh", "-", "-c", s, 0); write(2, "can't find shell\n", 17); exit(); } a[2] = (a[1]>>8)&0377; a[1] =& 0377; return(a); } ex_dfmt() { error("dfmt B"); } ex_mfmt() { ex_menc(); } ex_nc() { register struct nlist *np; register struct item *p; register char *q; int i; char buf[40]; p = fetch1(); if(p->type != CH) error("Lnc T"); if(p->size >= 40 || p->rank > 1) error("Lnc D"); copy(CH, p->datap, buf, p->size); buf[p->size] = 0; np = nlook(buf); i = 0; if(np != 0) switch(np->use){ case 0: i = 0; break; case MF: case NF: case DF: i = 3; break; case DA: case CH: case LV: i = 2; break; default: printf("unknown Lnc type = %d\n", np->use); i = 4; } p = newdat(DA, 0, 1); p->datap[0] = i; pop(); *sp++ = p; } qqG4/purdue/src/apl/an.c/* * name line */ char headline[] {"a p l \\ 1 1 \n2 Sep 1977\n\n"}; (qq4/purdue/src/apl/ao.c#include "apl.h" data ex_add(d1, d2) data d1, d2; { if(fuzz(d1, -d2) == 0) return(zero); return(d1 + d2); } data ex_sub(d1, d2) data d1, d2; { if(fuzz(d1, d2) == 0) return(zero); return(d1 - d2); } data ex_mul(d1, d2) data d1, d2; { return(d1 * d2); } data ex_div(d1, d2) data d1, d2; { /* 0 div 0 is NOT 1 */ if(d2 == zero) error("div D"); return(d1 / d2); } data ex_mod(d1, d2) data d1, d2; { double f; /* see 0 div 0 comment */ if(d1 == zero) error("mod D"); if(d1 < zero) d1 = -d1; f = d2; d2 = d2 - d1 * floor(f/d1); return(d2); } data ex_min(d1, d2) data d1, d2; { if(d1 < d2) return(d1); return(d2); } data ex_max(d1, d2) data d1, d2; { if(d1 > d2) return(d1); return(d2); } data ex_pwr(d1, d2) data d1, d2; { register s; double f1; s = 0; f1 = d1; if(f1 > 0.) { f1 = d2 * log(f1); goto chk; } if(f1 == 0.) { if(d2 == zero) goto bad; return(zero); } /* should check rational d2 here */ goto bad; chk: if(f1 < maxexp) { d1 = exp(f1); if(s) d1 = -d1; return(d1); } bad: error("pwr D"); } data ex_log(d1, d2) data d1, d2; { double f1, f2; f1 = d1; f2 = d2; if(f1 <= 0. || f2 <= 0.) error("log D"); d1 = log(f2)/log(f1); return(d1); } data ex_cir(d1, d2) data d1, d2; { double f, f1; switch(fix(d1)) { default: error("crc D"); case -7: /* arc tanh */ f = d2; if(f <= -1. || f >= 1.) error("tanh D"); f = log((1.+f)/(1.-f))/2.; goto ret; case -6: /* arc cosh */ f = d2; if(f < 1.) error("cosh D"); f = log(f+sqrt(f*f-1.)); goto ret; case -5: /* arc sinh */ f = d2; f = log(f+sqrt(f*f+1.)); goto ret; case -4: /* sqrt(-1 + x*x) */ f = -one + d2*d2; goto sq; case -3: /* arc tan */ f = d2; f = atan(f); goto ret; case -2: /* arc cos */ f = d2; if(f < -1. || f > 1.) error("arc cos D"); f = atan2(sqrt(1.-f*f), f); goto ret; case -1: /* arc sin */ f = d2; if(f < -1. || f > 1.) error("arc sin D"); f = atan2(f, sqrt(1.-f*f)); goto ret; case 0: /* sqrt(1 - x*x) */ f = one - d2*d2; goto sq; case 1: /* sin */ f = d2; f = sin(f); goto ret; case 2: /* cos */ f = d2; f = cos(f); goto ret; case 3: /* tan */ f = d2; f1 = cos(f); if(f1 == 0.) f = exp(maxexp); else f = sin(f)/f1; goto ret; case 4: /* sqrt(1 + x*x) */ f = one + d2*d2; goto sq; case 5: /* sinh */ f = d2; if(f < -maxexp || f > maxexp) error("sinh D"); f = exp(f); f = (f-1./f)/2.; goto ret; case 6: /* cosh */ f = d2; if(f < -maxexp || f > maxexp) error("cosh D"); f = exp(f); f = (f+1./f)/2.; goto ret; case 7: /* tanh */ f = d2; if(f > maxexp) { f = 1.; goto ret; } if(f < -maxexp) { f = -1.; goto ret; } f = exp(f); f = (f-1./f)/(f+1./f); goto ret; } sq: if(f < 0.) error("sqrt D"); f = sqrt(f); ret: d1 = f; return(d1); } data ex_comb(d1, d2) data d1, d2; { double f; if(d1 > d2) return(zero); f = gamma(d2+1.) - gamma(d1+1.) - gamma(d2-d1+1.); if(f > maxexp) error("comb D"); d1 = exp(f); return(d1); } data ex_and(d1, d2) data d1, d2; { if(d1!=zero && d2!=zero) return(one); return(zero); } data ex_or(d1, d2) data d1, d2; { if(d1!=zero || d2!=zero) return(one); return(zero); } data ex_nand(d1, d2) data d1, d2; { if(d1!=zero && d2!=zero) return(zero); return(one); } data ex_nor(d1, d2) data d1, d2; { if(d1!=zero || d2!=zero) return(zero); return(one); } data ex_lt(d1, d2) data d1, d2; { if(fuzz(d1, d2) < 0) return(one); return(zero); } data ex_le(d1, d2) data d1, d2; { if(fuzz(d1, d2) <= 0) return(one); return(zero); } data ex_eq(d1, d2) data d1, d2; { if(fuzz(d1, d2) == 0) return(one); return(zero); } data ex_ge(d1, d2) data d1, d2; { if(fuzz(d1, d2) >= 0) return(one); return(zero); } data ex_gt(d1, d2) data d1, d2; { if(fuzz(d1, d2) > 0) return(one); return(zero); } data ex_ne(d1, d2) data d1, d2; { if(fuzz(d1, d2) != 0) return(one); return(zero); } data ex_plus(d) data d; { return(d); } data ex_minus(d) data d; { return(-d); } data ex_sgn(d) data d; { if(d == zero) return(zero); if(d < zero) return(-one); return(one); } data ex_recip(d) data d; { if(d == zero) error("recip D"); return(one/d); } data ex_abs(d) data d; { if(d < zero) return(-d); return(d); } data ex_floor(d) data d; { d = floor(d + thread.fuzz); return(d); } data ex_ceil(d) data d; { d = ceil(d - thread.fuzz); return(d); } data ex_exp(d) data d; { double f; f = d; if(f > maxexp) error ("exp D"); d = exp(f); return(d); } data ex_loge(d) data d; { double f; f = d; if(f <= 0.) error("log D"); d = log(f); return(d); } data ex_pi(d) data d; { d = pi * d; return(d); } data ex_rand(d) data d; { double f; f = (rand()/32768.) * d; d = floor(f) + thread.iorg; return(d); } data ex_fac(d) data d; { double f; f = gamma(d+1.); if(f > maxexp) error("fac D"); d = exp(f); if(signgam) d = -d; return(d); } data ex_not(d) data d; { if(d == zero) return(one); return(zero); } Dq2q4/purdue/src/apl/apl.h/* * Temp file names */ #define WSFILE "apl_ws" /* work space file */ #define LPFILE "apl_lp" /* label preprocessor scratch file */ /* * Magic Numbers */ #define MRANK 8 #define CANBS 300 #define STKS 20 #define NLS 100 #define NAMS 20 #define OBJS 500 #define MAXLAB 30 #define MAGIC 0100554 #define data double /* * derrived constants */ #define SDAT sizeof datum #define SINT sizeof integ /* * Interpreter Op Codes */ #define EOF (-1) #define EOL 0 #define ADD 1 #define PLUS 2 #define SUB 3 #define MINUS 4 #define MUL 5 #define SGN 6 #define DIV 7 #define RECIP 8 #define MOD 9 #define ABS 10 #define MIN 11 #define FLOOR 12 #define MAX 13 #define CEIL 14 #define PWR 15 #define EXP 16 #define LOG 17 #define LOGE 18 #define CIR 19 #define PI 20 #define COMB 21 #define FAC 22 #define DEAL 23 #define RAND 24 #define DRHO 25 #define MRHO 26 #define DIOT 27 #define MIOT 28 #define ROT0 29 #define REV0 30 #define DTRN 31 #define MTRN 32 #define DIBM 33 #define MIBM 34 #define GDU 35 #define GDUK 36 #define GDD 37 #define GDDK 38 #define EXD 39 #define SCAN 40 #define EXDK 41 #define SCANK 42 #define IPROD 43 #define OPROD 44 #define QUAD 45 #define QQUAD 46 #define BRAN0 47 #define BRAN 48 #define DDOM 49 #define MDOM 50 #define COM 51 #define RED 52 #define COMK 53 #define REDK 54 #define ROT 55 #define REV 56 #define ROTK 57 #define REVK 58 #define CAT 59 #define RAV 60 #define CATK 61 #define RAVK 62 #define PRINT 63 #define QUOT 64 #define ELID 65 #define CQUAD 66 #define COMNT 67 #define INDEX 68 #define HPRINT 69 #define LT 71 #define LE 72 #define GT 73 #define GE 74 #define EQ 75 #define NE 76 #define AND 77 #define OR 78 #define NAND 79 #define NOR 80 #define NOT 81 #define EPS 82 #define MEPS 83 #define REP 84 #define TAKE 85 #define DROP 86 #define ASGN 88 #define IMMED 89 #define NAME 90 #define CONST 91 #define FUN 92 #define ARG1 93 #define ARG2 94 #define AUTO 95 #define REST 96 #define COM0 97 #define RED0 98 #define EXD0 99 #define SCAN0 100 #define BASE 101 #define MENC 102 /* monadic encode */ #define LABEL 103 /* statement label */ #define PSI 104 /* PSI input character */ #define PSI1 105 /* PSI monadic half */ #define PSI2 106 /* PSI dyadic half */ #define ISP 107 /* ISP input code */ #define ISP1 108 /* ISP monadic half */ #define ISP2 109 /* ISP dyadic half */ #define QWID 110 /* quad fn1 */ #define QFUZZ 111 #define QRUN 112 #define QFORK 113 #define QWAIT 114 #define QEXEC 115 #define FDEF 116 #define QEXIT 117 #define QPIPE 118 #define QCHDIR 119 #define QOPEN 120 #define QCLOSE 121 #define QREAD 122 #define QWRITE 123 #define QCREAT 124 #define QSEEK 125 #define QUNLNK 126 #define QRD 127 #define QDUP 128 #define QAP 129 #define QKILL 130 #define QCRP 131 #define DFMT 132 #define MFMT 133 #define QNC 134 #define NILRET 135 /* * Immediate sub-op codes */ #define CLEAR 1 #define DIGITS 2 #define EDIT 3 #define ERASE 4 #define FNS 5 #define FUZZ 6 #define READ 7 #define ORIGIN 8 #define VARS 9 #define WIDTH 10 #define DEBUG 11 #define OFF 12 #define LOAD 13 #define SAVE 14 #define COPY 15 #define CONTIN 16 #define LIB 17 #define DROPC 18 #define VSAVE 19 #define SCRIPT 20 struct { char c[0]; }; data zero; data one; data pi; data maxexp; data datum; data getdat(); struct { double fuzz; int iorg; int digits; int width; } thread; /* * Types */ #define DA 1 #define CH 2 #define LV 3 #define QD 4 #define QQ 5 #define IN 6 #define EL 7 #define NF 8 #define MF 9 #define DF 10 #define QC 11 #define QV 12 /* quad variables */ #define DU 13 /* dummy -- causes fetch error except on print */ struct item { char rank; char type; int size; int index; data *datap; int dim[0]; } *stack[STKS], **sp; struct nlist { char use; char type; /* == LV */ int *itemp; char *namep; int label; } nlist[NLS]; struct labtab { int ptr; int siz; } labtb[MAXLAB]; int (*exop[])(); double floor(); double ceil(); double log(); double sin(); double cos(); double atan(); double atan2(); double sqrt(); double exp(); double gamma(); double ltod(); int integ; int signgam; int column; int intflg; int echoflg; int ifile; int wfile; int funlc; int debug; int ttystat[3]; int stime[2]; char *pcp; /* global copy of arg to exec */ int rowsz; int mencflg; int aftrace; char *mencptr; int oldlb[MAXLAB]; int pt; int syze; int pas1; int ibeam36; int protofile; int lastop; /* last (current) operator exec'ed */ struct { char rank; char type; int size; int dimk; int delk; int dim[MRANK]; int del[MRANK]; int idx[MRANK]; } idx; mqSqS4/purdue/src/apl/apl.y%term lex0, lex1, lex2, lex3, lex4, lex5, lex6 %term lpar, rpar, lbkt, rbkt, eol, unk %term com, com0, strng, null, dot, cln %term quad, semi, comnt, tran, asg %term nam, numb, nfun, mfun, dfun %term comexpr, comnam, comnull %term dscal, mdscal %term m, d, md %term msub, mdsub, %{ #include "apl.h" int vcount; int scount; int litflag; int nlexsym; int context; char *iline; char *ccharp; %} %% /* * line-at-a-time APL compiler. * first lexical character gives context. */ line: /* * immediate. */ lex0 stat = { integ = ccharp[-1]; if(integ != ASGN && integ != PRINT && integ != COMNT) *ccharp++ = PRINT; *ccharp++ = EOL; } | lex0 bcomand comand eol = { *ccharp++ = IMMED; *ccharp++ = $3; } | /* * quad */ lex1 stat | /* * function definition */ lex2 func | /* * function prolog */ lex3 func | /* * function epilog */ lex4 func | /* * function body */ lex5 fstat ; /* * function header */ func: anyname asg header = { switch(context) { case lex3: name($$, AUTO); *ccharp++ = ELID; break; case lex4: integ = ccharp; *ccharp++ = EOL; name($$, NAME); name($$, REST); invert($3, integ); } } | header = { if(context == lex3) *ccharp++ = ELID; if(context == lex4) *ccharp++ = NILRET; /* return empty result */ } ; header: args autos = { if(context == lex4) invert($$, $2); } ; args: anyname anyname anyname = { $$ = ccharp; switch(context) { case lex2: name($2, DF); break; case lex3: name($3, ARG2); name($1, ARG1); break; case lex4: name($1, REST); name($3, REST); } } | anyname anyname = { $$ = ccharp; switch(context) { case lex2: name($1, MF); break; case lex3: name($2, ARG1); break; case lex4: name($2, REST); } } | anyname = { if(context == lex2) name($$, NF); $$ = ccharp; } ; autos: semi nam autos = { $$ = $3; switch(context) { case lex3: name($2, AUTO); break; case lex4: integ = name($2, REST); invert($$, integ); } } | eol = { $$ = ccharp; } ; /* * system commands */ bcomand: rpar = { litflag = -1; } ; comand: comexpr expr | comnam anyname = { name($2, NAME); } | comnull ; /* * statement: * comments * expressions * heterogeneous output * transfers (in functions) */ fstat: stat = { integ = ccharp[-1]; if(integ != ASGN && integ != PRINT && integ != COMNT) *ccharp++ = PRINT; } | tran eol = { $$ = ccharp; *ccharp++ = BRAN0; } | tran expr eol = { $$ = $2; *ccharp++ = BRAN; } ; stat: statement eol ; statement: comnt = { litflag = 1; $$ = ccharp; *ccharp++ = COMNT; } | expr | hprint ; hprint: expr hsemi output ; output: expr = { *ccharp++ = PRINT; } | hprint ; hsemi: semi = { *ccharp++ = HPRINT; }; expr: e1 | monadic expr = { invert($$, $2); } | e1 dyadic expr = { invert($$, $3); } ; e1: e2 | e2 lsub subs rbkt = { invert($$, $3); *ccharp++ = INDEX; *ccharp++ = scount; scount = $2; } ; e2: nfun = { $$ = name($$, FUN); } | nam = { $$ = name($$, NAME); } | strng = { $$ = ccharp; ccharp =+ 2; integ = iline[-1]; vcount = 0; for(;;) { if(*iline == '\n') { nlexsym = unk; break; } if(*iline == integ) { iline++; break; } *ccharp++ = *iline++; vcount++; } $$->c[0] = QUOT; $$->c[1] = vcount; } | vector = { *ccharp++ = CONST; *ccharp++ = vcount; invert($$, ccharp-2); } | lpar expr rpar = { $$ = $2; } | quad = { $$ = ccharp; *ccharp++ = $1; } ; vector: number vector = { vcount++; } | number = { vcount = 1; } ; number: numb = { $$ = ccharp; for(integ=0; integ 1){ close(0); if(open(argp[1], 0) != 0){ printf("can't open input file: %s\n", argp[1]); exit(1); } if(argc > 2){ close(1); if(creat(argp[2], 0644) != 1){ printf("can't create output file: %s\n", argp[2]); exit(2); } } } lstp=0; labcnt=0; while ((c= getchar()) != '\n'); /* skip first line*/ lincnt = 1; while ((c = getchar()) != '\0') { while (c == ' ') c= getchar (); lstpt = lstp; while ( ccheck(c) != 0) { lablst[lstpt++] = c; c=getchar (); } while (c == ' ') c=getchar(); if (c == ':'){ labn[labcnt]=lincnt; lstlst[labcnt]=lstp; lablst[lstpt++]='\0'; lstp = lstpt; labcnt++; } while (c != '\n') c=getchar (); lincnt++; } labnum = labcnt; labn[++labcnt] = 10000; /* pass 2 */ seek(0,0,0); while (putchar(getc()) != '\n') {} /* 1st line */ lincnt = 1; lstpt = 0; nt = labn[lstpt]; while( (c=getc()) != '\0') { if (nt < lincnt) nt = labn[++lstpt]; if (nt == lincnt) { /* get rid of label */ while( getc() != ':' ); c= getc(); } while (c != '\n') { if (ccheck(c) != 2){ if ( c== '\'' && clast != '\b') { putchar (c); if ((c=getc()) != '\b') {/* its a string*/ putchar(c); while (c != '\'' | clast == '\b' | (ct= getc()) == '\b') { putchar (c=ct);}/* output the string */ c=ct; } } else { putchar(c); c=getc(); } } else { obpt=0; obj[obpt++] = c; while(ccheck(c=getc()) != 0) obj[obpt++] = c; obj[obpt++]='\0'; m = match () ; if (m != 0) printf(" %d ",m); else { obpt=0; while ((ct=obj[obpt++])!='\0') putchar (ct); } } } putchar('\n'); lincnt++; } exit(0); /* successful exit */ } ccheck (cc) char cc ; { int res ; if (cc >= '0' && cc <= '9' ) res = 1; else if(cc >='a' && cc <= 'z') res = 2; else res =0; return (res); } match() { int mm; char cu,cs; mm=0; labcnt = 0; while (labcnt <= labnum-1 && mm==0) { lstp = lstlst[labcnt]; obpt =0; while ((cu=lablst[lstp++])==(cs= obj[obpt++]) && cu !='\0') {} if (cu==cs && cu == '\0') mm = labn[labcnt]; else labcnt++; } return (mm); } char getc() { clast=c; return (getchar()); } )q೗q4/purdue/src/apl/aq.c# /* * C library -- alloc/free */ #define logical char * int aftrace; struct fb { logical size; char *next; }; int freelist[] { 0, -1, }; logical slop 2; alloc(asize) logical asize; { register logical size; register logical np; register logical cp; if ((size = asize) == 0) return(0); size =+ 3; size =& ~01; if(aftrace) printf("alloc: %d\n", size); for (;;) { cp = freelist; while ((np = cp->next) != -1) { if (np->size>=size) { if (size+slop >= np->size) { cp->next = np->next; return(&np->next); } cp = cp->next = np+size; cp->size = np->size - size; cp->next = np->next; np->size = size; return(&np->next); } cp = np; } asize = size<1024? 1024: size; if ((cp = sbrk(asize)) == -1) { error("workspace exceeded"); } cp->size = asize; free(&cp->next); } } free(aptr) char *aptr; { register logical ptr; register logical cp; register logical np; if (aptr == 0) return; ptr = aptr-2; cp = freelist; if(aftrace) printf("free: %d\n", ptr->size); while ((np = cp->next) < ptr) cp = np; if (ptr+ptr->size == np) { ptr->size =+ np->size; ptr->next = np->next; np = ptr; } else ptr->next = np; if (cp+cp->size == ptr) { cp->size =+ ptr->size; cp->next = ptr->next; } else cp->next = ptr; } eq쳗q 4/purdue/src/apl/aw.c#include "apl.h" char *opname[] { "eol", /* 0 */ "add", /* 1 */ "plus", /* 2 */ "sub", /* 3 */ "minus", /* 4 */ "mul", /* 5 */ "sgn", /* 6 */ "div", /* 7 */ "recip", /* 8 */ "mod", /* 9 */ "abs", /* 10 */ "min", /* 11 */ "floor", /* 12 */ "max", /* 13 */ "ceil", /* 14 */ "pwr", /* 15 */ "exp", /* 16 */ "log", /* 17 */ "loge", /* 18 */ "cir", /* 19 */ "pi", /* 20 */ "comb", /* 21 */ "fac", /* 22 */ "deal", /* 23 */ "rand", /* 24 */ "drho", /* 25 */ "mrho", /* 26 */ "diot", /* 27 */ "miot", /* 28 */ "rot0", /* 29 */ "rev0", /* 30 */ "dtrn", /* 31 */ "mtrn", /* 32 */ "dibm", /* 33 */ "mibm", /* 34 */ "gdu", /* 35 */ "gduk", /* 36 */ "gdd", /* 37 */ "gddk", /* 38 */ "exd", /* 39 */ "scan", /* 40 */ "exdk", /* 41 */ "scank", /* 42 */ "iprod", /* 43 */ "oprod", /* 44 */ "quad", /* 45 */ "qquad", /* 46 */ "br0", /* 47 */ "br", /* 48 */ "ddom", /* 49 */ "mdom", /* 50 */ "com", /* 51 */ "red", /* 52 */ "comk", /* 53 */ "redk", /* 54 */ "rot", /* 55 */ "rev", /* 56 */ "rotk", /* 57 */ "revk", /* 58 */ "cat", /* 59 */ "rav", /* 60 */ "catk", /* 61 */ "ravk", /* 62 */ "print", /* 63 */ "quot", /* 64 */ "elid", /* 65 */ "cquad", /* 66 */ "comnt", /* 67 */ "index", /* 68 */ "hprint", /* 69 */ 0, /* 70 */ "lt", /* 71 */ "le", /* 72 */ "gt", /* 73 */ "ge", /* 74 */ "eq", /* 75 */ "ne", /* 76 */ "and", /* 77 */ "or", /* 78 */ "nand", /* 79 */ "nor", /* 80 */ "not", /* 81 */ "eps", /* 82 */ "meps", /* 83 */ "rep", /* 84 */ "take", /* 85 */ "drop", /* 86 */ "exd0", /* 87 */ "asgn", /* 88 */ "immed", /* 89 */ "name", /* 90 */ "const", /* 91 */ "fun", /* 92 */ "arg1", /* 93 */ "arg2", /* 94 */ "auto", /* 95 */ "rest", /* 96 */ "com0", /* 97 */ "red0", /* 98 */ "exd0", /* 99 */ "scan0", /*100 */ "base", /*101 */ "menc", /*102 */ /* monadic encode */ "label", /*103 */ "PSI", /*104 */ "PSI1", /*105 */ "PSI2", /*106 */ "ISP", /*107 */ "ISP1", /*108 */ "ISP2", /*109 */ "QWID", /*110 */ "QFUZZ", /*111 */ "QRUN", /*112 */ "QFORK", /*113 */ "QWAIT", /*114 */ "QEXEC", /*115 */ "QFDEF", /*116 */ "QEXIT", /*117 */ "Lpipe", /*118 */ "Lchdir", /*119 */ "Lopen", /*120 */ "Lclose", /*121 */ "Lread", /*122 */ "Lwrite", /*123 */ "Lcreat", /*124 */ "Lseek", /*125 */ "Lrm", /*126 */ "Lrd", /*127 */ "Ldup", /*128 */ "Lap", /*129 */ "Lkill", /*130 */ "Lcr", /*131 */ "dfmt", /*132 */ "mfmt", /*133 */ "Lnc", /*134 */ "nilret", /*135 */ }; dump(cp) char *cp; { register char *s, *t; register i; s = cp; loop: putchar(' '); if(column > 50) putchar('\n'); i = *s++; if(i != EOF) i =& 0377; if(i >= 0 && i <= 135 && opname[i]) { t = opname[i]; while(*t) putchar(*t++); } else if(i != EOF) printf("%d ", i); switch(i) { case EOL: if(*s != EOL) break; case EOF: putchar('\n'); return; case QUOT: i = *s++; s =+ i; break; case CONST: i = *s++; s =+ i*SDAT; break; case NAME: case FUN: case ARG1: case ARG2: case AUTO: case REST: s =+ copy(IN, s, &cp, 1); putchar('-'); t = cp->namep; while(*t) putchar(*t++); break; case INDEX: case IMMED: s++; break; } goto loop; } mqq4/purdue/src/apl/ax.s.globl fltused fltused = 0 eqq>4/purdue/src/apl/az.c#include "apl.h" /* * misc. other routines */ ex_exit() { exit(topfix()); } ex_fork() { register pid; register struct item *p; if(pid = fork()){ if(pid == -1) error("couldn't fork"); } pop(); iodone(pid); } ex_wait() { register struct item *p; register sig, pid; int s; sig = signal(2, 1); pid = wait1(&s); signal(2, sig); p = newdat(DA, 1, 3); p->datap[0] = pid; p->datap[1] = s&0377; p->datap[2] = (s>>8)&0377; pop(); /* dummy arg */ *sp++ = p; } #define MAXP 20 ex_exec() { register struct item *p; register i; register char *cp; char *argv[MAXP]; p = fetch1(); if(p->rank != 2 || p->dim[0] > MAXP || p->size > 500 || p->type != CH) error("Lexec D"); cp = p->datap; for(i=0; idim[0]; i++){ argv[i] = cp + i*p->dim[1]; } argv[p->dim[0]] = 0; execv(argv[0], &argv[1]); pop(); p = newdat(DA,0,0); *sp++ = p; } ex_chdir() { iodone(chdir(iofname())); } ex_write() { register int fd, m; register struct item *p; fd = topfix(); p = fetch1(); if(p->type != CH) error("Lwrite D"); m = write(fd, p->datap, p->size); pop(); iodone(m); } ex_creat() { register m; m = topfix(); iodone(creat(iofname(), m)); } ex_open() { register struct item *p; register m; m = topfix(); iodone(open(iofname(), m)); } ex_seek() { register struct item *p; int k1, k2, k3; p = fetch1(); if(p->type != DA || p->rank != 1 || p->size != 3) error("Lseek D"); k1 = p->datap[0]; k2 = p->datap[1]; k3 = p->datap[2]; k1 = seek(k1, k2, k3); pop(); iodone(k1); } ex_close() { iodone(close(topfix())); } ex_pipe() { register struct item *p; int pp[2]; if(pipe(pp) == -1) p = newdat(DA, 1, 0); else { p = newdat(DA, 1, 2); p->datap[0] = pp[0]; p->datap[1] = pp[1]; } pop(); *sp++ = p; } ex_read() { register struct item *p, *q; int fd, nb, c; fd = topfix(); nb = topfix(); p = newdat(CH, 1, nb); c = read(fd, p->datap, nb); if(c != nb){ q = p; if(c <= 0) p = newdat(CH, 1, 0); else { p = newdat(CH, 1, c); copy(CH, q->datap, p->datap, c); } dealloc(q); } *sp++ = p; } ex_unlink() { iodone(unlink(iofname())); } ex_kill() { register pid, signo; pid = topfix(); signo = topfix(); kill(pid, signo); *sp++ = newdat(DA, 1, 0); } ex_rd() { /* * note: * an empty line is converted to NULL. * no '\n' chars are returned. */ char buf[200]; register struct item *p; register fd, i; fd = topfix(); i = 0; while((read(fd, &buf[i], 1) == 1) && i < 200 && buf[i] != '\n') i++; if(i == 200) error("Lrd D"); if(i > 0){ p = newdat(CH, 1, i); copy(CH, buf, p->datap, i); } else p = newdat(CH, 1, 0); *sp++ = p; } ex_dup() { iodone(dup(topfix())); } ex_ap() { register i, fd; register struct item *p; fd = topfix(); p = fetch1(); seek(fd, 0, 2); fappend(fd, p); if(p->rank == 1) write(fd, "\n", 1); pop(); *sp++ = newdat(DA, 1, 0); } iodone(ok) { register struct item *p; p = newdat(DA, 0, 1); p->datap[0] = ok; *sp++ = p; } iofname(m) { register struct item *p; char b[200]; p = fetch1(); if(p->type != CH || p->rank > 1) error("file name D"); copy(CH, p->datap, b, p->size); b[p->size] = 0; pop(); return(b); } fappend(fd, ap) struct item *ap; { register struct item *p; register char *p1; int i, dim0, dim1, sb[32]; char b[200]; p = ap; if((p->rank != 2 && p->rank != 1) || p->type != CH) error("file append D"); dim1 = p->dim[1]; dim0 = p->dim[0]; if(p->rank == 1) dim1 = dim0; p1 = p->datap; if(p->rank == 2) for(i=0; idatap, dim0); } qA\4/purdue/src/apl/docqq!4/purdue/src/apl/doc/Ccc -c -f -O $1 $2 $3 $4 $5 $6 $7 wqqh4/purdue/src/apl/doc/CCcc -m -f -O -i $1 $2 $3 $4 $5 $6 $7 $8 $9 -u _main /usr/source/apl/lib -ly echo apl generation complete q "q%4/purdue/src/apl/doc/PR/bin/pr apl.h a?.c apl.y lex.c tab.c 8q 1q4/purdue/src/apl/doc/PRAPLnum gt $ <= le & >= ge = eq F =| =\ =/ ne ~ not ? deal rand R rho rho I iota iota E epsilon N represent B base \O trans trans , cat ravel * Y take U drop { <- assign } >- goto BN i-beam i-beam LP mat div inverse |H |A grade up * G| V| grade down * / comp * /- comp \ expand * \- expand O| rotate reverse * O- rotate reverse op/ reduce * op/- reduce J.op o prod op.op i prod * may be subscripted with a scalar Vq:qL4/purdue/src/apl/doc/changesFrom jim Mon May 16 04:10:47 1977 New changes to APL The following quad functions were added to facilitate UNIX process communication: val left fn right ret'd arg arg ---- ---- ---- ---- text -- Lrd fd (read 1 line) nil fd Lap text (append text) nnn pid Lkill signo (sends signal to process) nnn -- Ldup fd (duplicates file descriptor) nnn -- Lrm file (delete file) NOTES: nnn: value returned by system call (see chapter II) fd: file descriptor signo: a signal number (See kill(II) and signal(II)) file: a file name nil: null value text: a 1 or 2 dimensional character array. Lrd only returns 1 line at a time, and a completely blank line returns null, as will an end of file. A "Lrd domain" error occurs if the input line exceeds 200 characters. Lap accecpts 1 or 2 dimensional character arrays. One dimensional ones are written out as 1 line. Two dimensional arrays are written out with a '\n' between each horizontal row. The last character output by this command is always '\n'. From jim Wed May 11 23:18:19 1977 New changes to APL Wed May 11 22:10:27 EST 1977 The following quad functions were added to facilitate UNIX I/O: val left fn right ret'd arg arg ---- ---- ---- ---- fd mode Lopen file fd mode Lcreat file err -- Lclose fd pipes -- Lpipe dummy cnt fd Lread nb cnt fd Lwrite data err -- Lchdir file err -- Lseek (fd, pos, mode) mode: number indicating the mode of the open/close/seek fd: a file descriptor err: an error code (see chapter II) pipes: a 2R vector containing the two "pipe" file descriptors dummy: a dummy argument which must be supplied but which is ignored file: a nR character vector representing the file or directory to be manipulated. From jim Wed May 11 00:24:18 1977 Latest APL changes: Tue May 10 23:21:17 EST 1977 addition of ")vsave" system command. The )vsave command allows individual variables or functions to be selectivly saved in a workspace. The syntax is )vsave Vsave then prompts you for the names of variables/functions to be saved. After you'v entered the last one, a null name exits the prompt mode. The file is built and saved exactly as if it were an ordinary workspace. Note that the workspaces thus created are identical to any other workspace; in particular it retains the current "origin", "fuzz", etc., and could cause problems if you ")copy" the workspace in. (This is a general problem with apl, and wasn't introduced by this change.) From jim Tue May 10 00:12:46 1977 New/apl functions (9 may 77): Lexec xx: Takes a two dimensional character matrix, formats them into an "exec" call, and trys to exec that program. xx must be two dimensional, and each row corresponds to a different argument. The rows must be ZERO terminated. Lwait xx System wait call. Returns a 3-vector. The first element is the pid of the dead child (or -1 if there are none); the second is the status of the dead kid, and the third is the termination code returned by it. "xx" is a dummy argument which must be supplied, but is otherwise ignored. Lfork xx System fork call. returns pid in the parent, and 0 in the child. xx is a dummy arg. Lexit nn System exit call. nn is the process completion code, and is passed on to the parent. From jim Fri May 6 00:06:27 1977 *** more changes to APL *** 1) New version now accecpts full pathnames in ")" commands. (I.e. it allows '/'s.) 2) Alternate character set implimented. Alternate characters are formed by "F". Unfortunately, they are always printed by APL as 'F'. Also, 'F' all by itself is a legal identifier. This does not, I believe, conform strictly with APL conventions, but it's a day-one bug which would be fairly difficult to fix, and really shouldn't cause anyone any harm. 3) Lfx now accecpts an argument, x, EITHER of shape RRx=2 or RRx=1. In the first case, new-lines are inserted between rows, and in the second, new-line characters are assumed to be contained in the data. From jim Fri Apr 15 01:01:29 1977 A new "mail only" account has been set up to record updates to APL. You may mail to "apl", as any other user, and a copy gets put into /usr/news/apl/changes. (And also /usr/news/apl/.mail, a link to the above file). This makes it easier to keep track of these things. From jim Wed Apr 13 07:30:47 1977 new apl extensions (new/apl): 1) you may now take nothing and drop everything. 2) the debug output format has been improved slightly. 3) you may also take or drop a scalar. e.g. 1Y5 and 0Y5 yield 5 and , respectivly. (But 1 <--> R1Y5...) From tony Tue Apr 12 15:08:50 1977 Compress "/" has now been extended so that the right argument can be a scalar. Source of ad.c and /usr/bin/new/apl have been updated. A P L C H A N G E S 1) Branches can be made to the first element of a vector. Previously the argument to a branch operator had to have one or zero elements. There may be some unforeseen side effects from this change. 2) The Unix editor has been improved for apl. Better printing of line numbers and origin 0 have been added. 3) A preprocessor for labels has been added. Its operation will be invisible to the user. Feb 22, 1977 4) One element vectors are now extended for dyadic scaler operators when both arguments are not the same shape .This is the same as APL/360, previously only scaler arguments were extended. 5) Currently the best way to realize the "=" operator with character operands is to use something like the following: [0] z_ x cheq y [1] z_ 1 U (1,x) = 1,y 6) A new set of chacters has been installed. It is now possible to make the apl text look better when usin different types of terminal. See "help apl/characters" for details. 7) The apl interpereter now uses seperate i and d space. This means that the workspace size is now much larger. 8) Monadic eps "E" the execute operator has been modifyed so that a zero length argument is accepted (as in apl/360). From jim Mon Apr 11 23:13:44 1977 (Yet another) New version of APL. This one has only a few changes, most importantly: Lfx quad function 'fixes' a function definition. Given a rectangular character array, it treats it as a function definion (as returned by B'...'), and records it in the system. '/-' has replaced '/*' (reduce along last coordinate) '\-' replaces '\*' (expand along last coordinate) From jim Mon Apr 11 15:02:50 1977 New version of APL. minor changes: 'Y~' and 'U~' are synomynous with 'Y-' and 'U-', respectivly. Also the following new characters were defined: 'X' for multiply (In addition to 'M') '%' for divide (in addition to 'P' (bleah)) From jim Fri Apr 8 16:40:54 1977 new version of apl. recognizes quad-function "Lcr" (same as monadic encode on char string). The '&' char, previously an AND operator, has been changed to be the GREATER-EQUAL operator. The '@' character (previously GREATER-EQUAL) is now similar to ALPHA. 'A' and '^' still operate as AND, and 'A~', '^~' and '&~' still operate as NAND. It also recognizes 'Y-' and 'U-' as legal overstrikes, but have no function definition. --jb qqY4/purdue/src/apl/doc/charssFollowing is the character set used by APL. Note that it requires full uppper/lower case and/or overprinting. a-z letter 0-9 digit ` negative sign '--' string C J C comment . ( ) [ ; ] indexing L quad L ' quot quad diadic monadic + add plus - sub negate M mult sign X mult sign P div recip % div recip | mod abs D min floor S max ceil * pwr exp O * log loge O circ pi times ' . comb fact ! comb fact A and ^ and V or Q or & ~ nand ^ ~ nand A ~ nand V ~ nor Q ~ nor < lt > gt $ le & ge = eq # ne / = ne ~ not ? deal rand R rho rho I iota iota E epsilon N represent B base \ O trans trans , cat ravel * Y take U drop _ assign { assign } goto B N i-beam i-beam L P mat div inverse | H grade up * | A grade up * | V grade dn * G | grade down * / comp * / - comp \ expand * \ - expand O | rotate reverse * O - rotate reverse op/ reduce * op/ - reduce J.op o prod op.op i prod * may be subscripted with a scalar backspace (ctrl h) lqyq4/purdue/src/apl/doc/debugs The following table may be of some use when the ")debug" system command is used. "eol", /* 0 */ "add", /* 1 */ "plus", /* 2 */ "sub", /* 3 */ "minus", /* 4 */ "mul", /* 5 */ "sgn", /* 6 */ "div", /* 7 */ "recip", /* 8 */ "mod", /* 9 */ "abs", /* 10 */ "min", /* 11 */ "floor", /* 12 */ "max", /* 13 */ "ceil", /* 14 */ "pwr", /* 15 */ "exp", /* 16 */ "log", /* 17 */ "loge", /* 18 */ "cir", /* 19 */ "pi", /* 20 */ "comb", /* 21 */ "fac", /* 22 */ "deal", /* 23 */ "rand", /* 24 */ "drho", /* 25 */ "mrho", /* 26 */ "diot", /* 27 */ "miot", /* 28 */ "rot0", /* 29 */ "rev0", /* 30 */ "dtrn", /* 31 */ "mtrn", /* 32 */ "dibm", /* 33 */ "mibm", /* 34 */ "gdu", /* 35 */ "gduk", /* 36 */ "gdd", /* 37 */ "gddk", /* 38 */ "exd", /* 39 */ "scan", /* 40 */ "exdk", /* 41 */ "scank", /* 42 */ "iprod", /* 43 */ "oprod", /* 44 */ "quad", /* 45 */ "qquad", /* 46 */ "br0", /* 47 */ "br", /* 48 */ "ddom", /* 49 */ "mdom", /* 50 */ "com", /* 51 */ "red", /* 52 */ "comk", /* 53 */ "redk", /* 54 */ "rot", /* 55 */ "rev", /* 56 */ "rotk", /* 57 */ "revk", /* 58 */ "cat", /* 59 */ "rav", /* 60 */ "catk", /* 61 */ "ravk", /* 62 */ "print", /* 63 */ "quot", /* 64 */ "elid", /* 65 */ "cquad", /* 66 */ "comnt", /* 67 */ "index", /* 68 */ "hprint", /* 69 */ 0, /* 70 */ "lt", /* 71 */ "le", /* 72 */ "gt", /* 73 */ "ge", /* 74 */ "eq", /* 75 */ "ne", /* 76 */ "and", /* 77 */ "or", /* 78 */ "nand", /* 79 */ "nor", /* 80 */ "not", /* 81 */ "eps", /* 82 */ "meps", /* 83 */ "rep", /* 84 */ "take", /* 85 */ "drop", /* 86 */ "exd0", /* 87 */ "asgn", /* 88 */ "immed", /* 89 */ "name", /* 90 */ "const", /* 91 */ "fun", /* 92 */ "arg1", /* 93 */ "arg2", /* 94 */ "auto", /* 95 */ "rest", /* 96 */ "com0", /* 97 */ "red0", /* 98 */ "exd0", /* 99 */ "scan0", /*100 */ "base", /*101 */ "menc", /*102 */ /* monadic encode */ "label", /*103 */ q紗q34/purdue/src/apl/doc/descrptNAME apl - APL interpreter SYNPOSIS apl DESCRIPTION This is a preliminary version of APL which has been installed by popular demmand. ****use at your own risk****. The interperetor started life at bell labs, then went to yale and finally came to Purdue via Chicago. We have only had it a couple of weeks and many changes will be made in the near future. So if something suddenly does not work first check with "help apl/changes". Function definition is not what you would expect. Functions are loaded from files. The first line of the file is the function header, as you would expect it but with no del. The rest of the file is the lines of the function. Lines are numbered, but there's none of the square bracket jazz. If you say )READ FILE it will load the function in that file. If you say )EDIT FILE it will put you in the unix editor to change that file. Upon exit, it will read the file in as though by )READ. All of the usual operators are available, including domino. BUGS I don't know of too many, but mail any trouble reports to reeves. Interpreter occasionally blows up. Character comparisons don't work (but try concatenating a character vector to a numeric vector and vice versa.) Many mixed functions take less general arguments than you might expect. Then again any integer origin is allowed. qq]4/purdue/src/apl/doc/gentocgrep -n "^[a-z0-9 _]*(.*)$" *.c^\ sort -t: +2 ^\ tr : ' ' >TOC echo TOC generation complete sqᴗq24/purdue/src/apl/doc/read.meThis is the Unix APL interpreter, originally written by Ken Thompson, and fixed up a lot by John Levine and a cast of hundreds at Yale. Peculiarities: This APL expects some APL terminals which can be put in APL mode with a funny control sequence. It also expects that if you do a special stty call, it will not treat @ and # as special and it will break on an . All this is in aplmod/a0.c. It will also work in raw mode, except that then you can't DEL out of it. It expects your terminals to be normal ASCII terminals with APL key tops. The translation table is in tab.c, and some of the lexical analysis in tab.c would have to be changed a little. Line editing works and uses where other APL's use line feed. At Yale we use separated I/D space with APL. Other places probably shouldn't because 1) it uses the system wait() routine which calls nargs() (which works with I/D space at Yale for complicated reasons) and 2) the mathematical functions in /lib/liba.a all have to be modified to work right with I/D space. This version of APL has most of the features that APL\360 had when the domino (matrix divide) operator was added. There is none of the shared variable stuff. You can load and save workspaces, but there is no state indicator. There is also monadic epsilon (execute) and monadic base (function -> characted array). Functions still don't have labels, since the code for it was written and then lost. Comparing characters doesn't work but you might try concatenating a character vector with a numerical vector. There are some Dartmouth-style plotting functions in ak.c which expect to find functions called move, line, and sclr in the library. These should be turned off or commented out or something. Installation instructions: look at file run to install it, and at rc to recompile changed parts. q۴qZ4/purdue/src/apl/doc/run.: install APL as ax.s;mv a.out ax.o yacc apl.y cc -f -n -O a?.c y.tab.c ax.o mv a.out apl q괗q-4/purdue/src/apl/doc/sys.cmdsAPL System commands. There are a whole bunch of them. Most are pretty familiar. )DIGITS n sets the number of digits displayed to n, from 1 to 19. )FUZZ n sets the fuzz to n. )ORIGIN n sets the origin to n, which can be any integer, not just 1 or 0 )WIDTH n sets APL's idea of your terminal's carriage width. )ERASE n gets rid of function or variable named n. )SAVE n saves all variables and functions in file named n. The format used is peculiar to APL workspaces and can only be read back in by APL. )LOAD n gets the stuff in file n (which must have been saved) back. )COPY n like )LOAD but variables and functions are not erased. Things in the loaded file take precedence over stuff already in. )CLEAR discards everything. )DROP n deletes file n, which need not be saved from APL. )CONTINUE does what you'd expect. )OFF exits, as does ctrl/d. )READ n reads in a function from file n. The first line is the header, with no del's. The full APL\360 header is accepted. All other lines in the file are lines in the function. Lines are impli- citly numbered, and transfers are as usual.There are no labels. )EDIT n runs the UNIX editor on file n, and then READ's it when you leave the editor. )LIB lists out all of the files in the current directory. )FNS lists out all current functions. )VARS lists out all current variables. )DEBUG toggles a debugging switch, which can produce vast amounts of hopelessly cryptic output. If you find bugs, have comments, or anything else having to do with APL, please mail them to user "reeves". eqq4/purdue/src/apl/doc/y.tab.cqq4/purdue/src/apl/doc/yacc.actsqq4/purdue/src/apl/doc/yacc.tmpqqW4/purdue/src/apl/entercenter L _ 'enter text:' L _ '(interrupt to exit)' text _ '' l: text _ text, L', 10 }l eqq4/purdue/src/apl/lex.cc#define lv yylval #define v yyval int xxpeek[2] {0,0}; yylex() { register c, rval; register struct tab *tp; if(nlexsym != -1) { c = nlexsym; nlexsym = -1; return(c); } while(litflag > 0) { /* comment */ c = *iline++; if(c == '\n') { nlexsym = 0; return(eol); } } if(xxpeek[0] != 0){ lv = xxpeek[0]; xxpeek[0] = 0; return(xxpeek[1]); } do c = *iline++; while(c == ' '); if(c == '\n') { nlexsym = 0; return(eol); } if(alpha(c)) return(getnam(c)); if(digit(c) || c == '`' || /* '`' was '"' */ (c=='.' && digit(*iline))) return(getnum(c)); c =& 0377; rval = unk; for(tp = tab; tp->input; tp++) if(tp->input == c) { lv = tp->lexval; rval = tp->retval; break; } if(lv == QUAD) return(getquad()); if(lv == ISP){ lv = ISP2; xxpeek[0] = ISP1; xxpeek[1] = m; return(d); } if(lv == PSI){ lv = PSI2; xxpeek[0] = PSI1; xxpeek[1] = m; return(d); } return(rval); } getquad() { register char c, *p1; register struct qtab *p2; char qbuf[10]; p1 = qbuf; while(alpha(*iline)) *p1++ = *iline++; *p1++ = 0; if(*qbuf == 0) return(quad); /* ordinary quad */ for(p2= &qtab; p2->qname; p2++){ if(equal(p2->qname, qbuf)){ lv = p2->qtype; return(p2->rtype); } } return(unk); } getnam(ic) { char name[NAMS]; register c; register char *cp; register struct nlist *np; cp = name; do { if(cp >= &name[NAMS]) error("var name D"); *cp++ = c; c = *iline++; } while(alpha(c) || digit(c)); *cp++ = 0; iline--; if(litflag == -1) { /* commands */ litflag = -2; for(c=0; comtab[c]; c=+3) if(equal(name, comtab[c])) break; lv = comtab[c+2]; return(comtab[c+1]); } for(np=nlist; np->namep; np++) if(equal(np->namep, name)) { lv = np; switch(np->use) { case NF: return(nfun); case MF: return(mfun); case DF: return(dfun); } return(nam); } np->namep = alloc(cp-name); copy(CH, name, np->namep, cp-name); np->type = LV; lv = np; return(nam); } getnum(ic) { double d1, d2; register c, n, n1; int s, s1; s = 0; n = 0; d1 = 0.; c = ic; if(c == '`') { /* '`' was '"' */ s++; c = *iline++; } while(digit(c)) { d1 = d1*10. + c - '0'; c = *iline++; } if(c == '.') { c = *iline++; while(digit(c)) { d1 = d1*10. + c - '0'; c = *iline++; n--; } } if(c == 'e') { s1 = 0; n1 = 0; c = *iline++; if(c == '`') { /* '`' was '"' */ s1++; c = *iline++; } while(digit(c)) { n1 = n1*10 + c - '0'; c = *iline++; } if(s1) n =- n1; else n =+ n1; } n1 = n; if(n1 < 0) n1 = -n1; d2 = 1.; while(n1--) d2 =* 10.; if(n < 0) d1 =/ d2; else d1 =* d2; if(s) d1 = -d1; iline--; datum = d1; return(numb); } alpha(s) { register c; c = s & 0377; return( (c >= 'a' && c <= 'z') || (c == 'F') || (c >= 0243) || (litflag == -2 && ( c == '/' || c == '.' )) ); } digit(s) { register c; c = s; if(c >='0' && c <= '9') return(1); return(0); } /* * s is statement * f is execution flag: * 0 compile immediate * 1 compile L * 2 function definition * 3 function prolog * 4 function epilog * 5 function body */ int ilex[] { lex0, lex1, lex2, lex3, lex4, lex5, lex6 }; compile(s, f) { register char *p, *q; char oline[OBJS]; iline = s; ccharp = oline; litflag = 0; nlexsym = ilex[f]; context = nlexsym; if(yyparse()) { pline(s, iline-s); if(iline-s > 1) printf("Syntax error\n"); return(0); } *ccharp++ = EOF; p = alloc(ccharp-oline); iline = p; for(q=oline; q', GT,dscal, '$', LE,dscal, 0220, LE,dscal, '&', GE,dscal, 0221, GE,dscal, '=', EQ,dscal, '#', NE,dscal, 0222, NE,dscal, '^', AND,dscal, 'A', AND,dscal, 'Q', OR,dscal, 'V', OR,dscal, 0205 , NAND,dscal, 0231, NAND,dscal, 0206 , NOR,dscal, 0223, NAND,dscal, 0224, NOR,dscal, /* * monadic or dyadic scalars * op2 op1 v (dyadic op) * op1 v+1 (monadic op) */ '+', ADD,mdscal, '-', SUB,mdscal, 'M', MUL,mdscal, 'X', MUL,mdscal, 0225, MUL,mdscal, 'P', DIV,mdscal, 0240, DIV,mdscal, '%', DIV,mdscal, 0226, DIV,mdscal, '|', MOD,mdscal, 'D', MIN,mdscal, 'S', MAX,mdscal, '*', PWR,mdscal, 0207 , LOG,mdscal, 'O', CIR,mdscal, 0210 , COMB,mdscal, '!', COMB,mdscal, /* * monadic * op1 v (monadic op) */ '~', NOT,m, 0241, EPS+1,m, /* * dyadic * op2 op1 v (dyadic op) */ 'N', REP,d, 'Y', TAKE,d, 'U', DROP,d, '_', ASGN,asg, '{', ASGN,asg, /* * monadic or dyadic * op2 op1 v (dyadic op) * op1 v+1 (monadic op) */ 'E', EPS,md, 'B', BASE,md, '?', DEAL,md, 'R', DRHO,md, 'I', DIOT,md, 0211 , ROT0,md, 0212 , DTRN,md, 0213 , DIBM,md, 0214 , DDOM,md, 0242, DFMT,md, /* * monadic with optional subscript * op1 v (monadic op) * op1 sub v+1 (subscripted monadic op) */ 0215 , GDU,msub, 0216 , GDD,msub, 0227, GDU,msub, 0230, GDD,msub, /* * dyadic with optional subscript * op2 op1 v (dyadic op) * op2 op1 sub v+1 (subscripted dyadic op) */ /* * monadic or dyadic with optional subscript * op2 op1 v (dyadic op) * op1 v+1 (monadic op) * op2 op1 sub v+2 (subscripted dyadic op) * op1 sub v+3 (subscripted monadic op) */ 0217 , ROT,mdsub, ',', CAT,mdsub, /* * ISP and PSI */ 0232, PSI,d, 0233, ISP,d, /* * other, non-function */ 0234, unk,null, 0235, unk,null, 0236, unk,null, 0237, unk,null, '@', unk,null, /* * end of list */ 0 }; int comtab[] { "clear", comnull, CLEAR, "continue", comnull, CONTIN, "copy", comnam, COPY, "debug", comnull, DEBUG, "digits", comexpr, DIGITS, "drop", comnam, DROPC, "edit", comnam, EDIT, "erase", comnam, ERASE, "fns", comnull, FNS, "fuzz", comexpr, FUZZ, "lib", comnull, LIB, "load", comnam, LOAD, "off", comnull, OFF, "origin", comexpr, ORIGIN, "read", comnam, READ, "save", comnam, SAVE, "vars", comnull, VARS, "width", comexpr, WIDTH, "vsave", comnam, VSAVE, "script", comnam, SCRIPT, 0, unk }; /* * List of two-character escapes. Indexed by 02XX entries * in "tab", above. Entries must be in lexical order, i.e. * 'V~' will work, '~V' will not (since overstrikes are * sorted before they are looked up). 'V~' is 6 down in * the table, and thus corresponds to 0206, * which "tab" shows to be NOR. */ int chartab[] { '-/', /* 0200 comprs */ '-\\', /* 0201 expand */ '\'L', /* 0202 quote quad */ 'LO', /* 0203 circle quad */ 'CJ', /* 0204 lamp */ '^~', /* 0205 nand */ 'V~', /* 0206 nor */ '*O', /* 0207 log */ '\'.', /* 0210 comb/fact ('!') */ '-O', /* 0211 rotate */ 'O\\', /* 0212 transpose */ 'BN', /* 0213 i beam */ 'LP', /* 0214 domino */ 'A|', /* 0215 grade up */ 'V|', /* 0216 grade dn */ 'O|', /* 0217 rotate */ '<=', /* 0220 less eq */ '=>', /* 0221 greater eq */ '/=', /* 0222 not eq */ 'A~', /* 0223 nand */ 'Q~', /* 0224 nor */ '/\\', /* 0225 multiply */ '-:', /* 0226 divide */ 'H|', /* 0227 another grade up */ 'G|', /* 0230 another dgrade dn */ '&~', /* 0231 yet another nand */ 'U|', /* 0232 PSI */ 'C|', /* 0233 ISP */ 'Y~', /* 0234 bracket 1 */ 'U~', /* 0235 bracket 2 */ '-U', /* 0236 another bracket 2 */ '-Y', /* 0237 another bracket 2 */ '//', /* 0240 alternate divide */ 'BJ', /* 0241 standard execute */ 'JN', /* 0242 format */ /* * function alpha() in lex.c must be changed whenever this * table is updated. It must know the index of the alternate * character set (currently 0243) */ 'Fa', /* alternate character set */ 'Fb', 'Fc', 'Fd', 'Fe', 'Ff', 'Fg', 'Fh', 'Fi', 'Fj', 'Fk', 'Fl', 'Fm', 'Fn', 'Fo', 'Fp', 'Fq', 'Fr', 'Fs', 'Ft', 'Fu', 'Fv', 'Fw', 'Fx', 'Fy', 'Fz', 0 }; /* * qtab -- table of valid quad functions * the format of the qtab is the similar to tab, above * */ struct qtab{ char *qname; int qtype; int rtype; } qtab[] { "width", QWID, quad, "run", QRUN, m, "fuzz", QFUZZ, quad, "fork", QFORK, m, "wait", QWAIT, m, "exec", QEXEC, m, "cr", QCRP, m, "fx", FDEF, m, "exit", QEXIT, m, "pipe", QPIPE, m, "chdir",QCHDIR, m, "open", QOPEN, d, "close", QCLOSE, m, "read", QREAD, d, "write",QWRITE, d, "creat",QCREAT, d, "seek", QSEEK, m, "kill", QKILL, d, "rd", QRD, m, "rm", QUNLNK, m, "dup", QDUP, m, "ap", QAP, d, "rline",QRD, m, "nc", QNC, m, 0}; q8q4/purdue/src/apl/wait0.s./ C library -- wait0 / pid = wait0(); / / pid == -1 if error / no status is returned / / this routine included for seperated I/D programs .globl _wait0, cerror _wait0: mov r5,-(sp) mov sp,r5 sys wait bec 1f tst (sp)+ jmp cerror 1: mov (sp)+,r5 rts pc q&qA4/purdue/src/apl/wait1.s./ C library -- wait1 / pid = wait1(&status); / / pid == -1 if error / status indicates fate of process, if given / / this routine included for seperated I/D programs .globl _wait1, cerror _wait1: mov r5,-(sp) mov sp,r5 sys wait bec 1f tst (sp)+ jmp cerror 1: mov r1,*4(r5) / status return mov (sp)+,r5 rts pc aq5q14/purdue/src/apl/y.tab.c.# define lex0 257 # define lex1 258 # define lex2 259 # define lex3 260 # define lex4 261 # define lex5 262 # define lex6 263 # define lpar 264 # define rpar 265 # define lbkt 266 # define rbkt 267 # define eol 268 # define unk 269 # define com 270 # define com0 271 # define strng 272 # define null 273 # define dot 274 # define cln 275 # define quad 276 # define semi 277 # define comnt 278 # define tran 279 # define asg 280 # define nam 281 # define numb 282 # define nfun 283 # define mfun 284 # define dfun 285 # define comexpr 286 # define comnam 287 # define comnull 288 # define dscal 289 # define mdscal 290 # define m 291 # define d 292 # define md 293 # define msub 294 # define mdsub 295 #include "apl.h" int vcount; int scount; int litflag; int nlexsym; int context; char *iline; char *ccharp; #define yyclearin yychar = -1 #define yyerrok yyerrflag = 0 extern int yychar, yyerrflag; #ifndef YYMAXDEPTH #define YYMAXDEPTH 150 #endif #ifndef YYSTYPE #define YYSTYPE int #endif #ifndef YYVCOPY #define YYVCOPY(x,y) x=y #endif YYSTYPE yylval, yyval; # define YYERRCODE 256 #include "tab.c" #include "lex.c" int yyexca[] { -1, 1, 0, -1, -2, 0, -1, 29, 266, 58, -2, 56, -1, 31, 266, 59, -2, 79, -1, 32, 270, 80, 271, 80, 274, 80, -2, 77, -1, 65, 274, 81, -2, 70, -1, 69, 266, 76, -2, 74, -1, 71, 266, 75, -2, 79, }; # define YYNPROD 86 # extern int yychar; int yylast 219; yyact[]{ 26, 33, 111, 52, 53, 54, 82, 41, 24, 42, 43, 44, 27, 36, 12, 50, 108, 23, 36, 22, 20, 57, 98, 97, 109, 33, 32, 28, 89, 35, 29, 31, 26, 11, 41, 55, 42, 43, 44, 86, 24, 115, 104, 113, 27, 76, 12, 74, 85, 23, 36, 22, 20, 114, 78, 79, 26, 33, 32, 28, 87, 35, 29, 31, 24, 84, 100, 14, 27, 40, 70, 60, 59, 23, 36, 22, 20, 21, 75, 30, 26, 33, 32, 28, 25, 35, 29, 31, 24, 77, 19, 18, 27, 63, 12, 64, 26, 23, 36, 22, 20, 39, 34, 13, 24, 33, 32, 28, 27, 35, 29, 31, 99, 23, 36, 22, 20, 73, 17, 81, 72, 33, 32, 28, 94, 35, 29, 31, 69, 67, 80, 62, 2, 3, 4, 5, 6, 7, 68, 96, 58, 83, 16, 61, 15, 92, 56, 65, 32, 10, 66, 35, 105, 71, 88, 91, 90, 103, 38, 8, 93, 45, 95, 37, 46, 47, 48, 49, 51, 9, 1, 0, 0, 0, 116, 110, 112, 101, 0, 0, 102, 117, 0, 0, 106, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101 }; yypact[]{ -125,-1000,-232,-184,-247,-247,-247,-264,-1000,-283, -233,-1000,-1000,-256,-1000,-142,-168,-219,-1000,-221, -1000,-216,-1000,-1000,-1000,-1000,-168,-1000,-1000,-1000, -1000,-1000,-1000,-1000,-269,-1000,-1000,-1000,-1000,-274, -1000,-1000,-1000,-1000,-1000,-229,-1000,-1000,-1000,-1000, -208,-240,-168,-247,-1000,-1000,-168,-1000,-168,-1000, -221,-1000,-251,-252,-1000,-1000,-1000,-1000,-1000,-1000, -1000,-1000,-1000,-168,-1000,-1000,-168,-1000,-221,-1000, -223,-1000,-247,-247,-1000,-265,-1000,-1000,-244,-1000, -1000,-1000,-1000,-256,-1000,-1000,-1000,-288,-288,-224, -1000,-1000,-226,-1000,-1000,-1000,-247,-1000,-229,-1000, -1000,-1000,-1000,-1000,-168,-1000,-1000,-1000 }; yypgo[]{ 0, 170, 159, 169, 168, 158, 166, 101, 69, 161, 65, 103, 149, 67, 146, 145, 144, 142, 140, 118, 117, 112, 84, 102, 66, 91, 90, 78, 77, 89, 79, 72, 71, 70 }; yyr1[]{ 0, 1, 1, 1, 1, 1, 1, 1, 5, 5, 8, 9, 9, 9, 10, 10, 3, 4, 4, 4, 6, 6, 6, 2, 12, 12, 12, 13, 15, 15, 14, 11, 11, 11, 16, 16, 19, 19, 19, 19, 19, 19, 22, 22, 23, 20, 21, 21, 24, 24, 17, 17, 17, 17, 17, 25, 25, 25, 26, 26, 18, 18, 18, 18, 18, 32, 27, 29, 29, 31, 31, 31, 31, 31, 31, 33, 33, 30, 30, 30, 28, 28, 7, 7, 7, 7 }; yyr2[]{ 0, 2, 4, 2, 2, 2, 2, 2, 3, 1, 2, 3, 2, 1, 3, 1, 1, 2, 2, 1, 1, 2, 3, 2, 1, 1, 1, 3, 1, 1, 1, 1, 2, 3, 1, 4, 1, 1, 1, 1, 3, 1, 2, 1, 1, 1, 1, 3, 1, 0, 1, 2, 1, 2, 3, 1, 1, 1, 1, 1, 1, 2, 1, 3, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; yychk[]{ -1000, -1, 257, 258, 259, 260, 261, 262, -2, -3, -12, 265, 278, -11, -13, -16, -17, -19, -25, -26, 284, -28, 283, 281, 272, -22, 264, 276, 291, 294, -30, 295, 290, 289, -23, 293, 282, -2, -5, -7, -8, 281, 283, 284, 285, -9, -5, -5, -6, -2, 279, -4, 286, 287, 288, 268, -14, 277, -18, -31, -32, 285, 273, -28, -30, 289, 292, 271, 280, 270, -33, 295, -11, -20, 266, -27, 266, -29, 270, 271, -11, -22, 280, -7, -10, 277, 268, 268, -11, 268, -11, -7, -15, -11, -13, -11, -27, 274, 274, -21, -24, -11, -11, -27, 265, -8, -7, -7, 281, 268, -28, 290, -28, 267, 277, 267, -10, -24 }; yydef[]{ 0, -2, 0, 0, 0, 0, 0, 0, 1, 0, 0, 16, 24, 25, 26, 31, 0, 34, 50, 0, 52, 0, 36, 37, 38, 39, 0, 41, 55, -2, 57, -2, -2, 81, 43, 78, 44, 3, 4, 13, 9, 82, 83, 84, 85, 0, 5, 6, 7, 20, 0, 0, 0, 0, 19, 23, 0, 30, 0, 60, 0, 62, 0, 0, 69, -2, 71, 72, 73, -2, 65, -2, 32, 49, 45, 51, 0, 53, 67, 68, 0, 42, 0, 12, 10, 0, 15, 21, 0, 2, 17, 18, 27, 28, 29, 33, 61, 0, 0, 0, 46, 48, 0, 54, 40, 8, 13, 11, 0, 22, 63, 80, 64, 35, 49, 66, 14, 47 }; # # define YYFLAG -1000 # define YYERROR goto yyerrlab # define YYACCEPT return(0) # define YYABORT return(1) /* parser for yacc output */ int yydebug 0; /* 1 for debugging */ YYSTYPE yyv[YYMAXDEPTH]; /* where the values are stored */ int yychar -1; /* current input token number */ int yynerrs 0; /* number of errors */ int yyerrflag 0; /* error recovery flag */ yyparse() { int yys[YYMAXDEPTH]; int yyj, yym; register YYSTYPE *yypvt; register yystate, *yyps, yyn; register YYSTYPE *yypv; register *yyxi; yystate = 0; yychar = -1; yynerrs = 0; yyerrflag = 0; yyps= &yys[-1]; yypv= &yyv[-1]; yystack: /* put a state and value onto the stack */ if( yydebug ) printf( "state %d, value %d, char %d\n",yystate,yyval,yychar ); if( ++yyps> &yys[YYMAXDEPTH] ) yyerror( "yacc stack overflow" ); *yyps = yystate; ++yypv; YYVCOPY(*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; YYVCOPY(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 */ if( yydebug ) printf( "error recovery pops state %d, uncovers %d\n", *yyps, yyps[-1] ); --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 */ if( yydebug ) printf( "error recovery discards char %d\n", yychar ); if( yychar == 0 ) goto yyabort; /* don't discard EOF, quit */ yychar = -1; goto yynewstate; /* try again in the same state */ } } /* reduction by production yyn */ if( yydebug ) printf("reduce %d\n",yyn); yyps =- yyr2[yyn]; yypvt = yypv; yypv =- yyr2[yyn]; YYVCOPY(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 1: { integ = ccharp[-1]; if(integ != ASGN && integ != PRINT && integ != COMNT) *ccharp++ = PRINT; *ccharp++ = EOL; } break; case 2: { *ccharp++ = IMMED; *ccharp++ = yypvt[-1]; } break; case 8: { switch(context) { case lex3: name(yyval, AUTO); *ccharp++ = ELID; break; case lex4: integ = ccharp; *ccharp++ = EOL; name(yyval, NAME); name(yyval, REST); invert(yypvt[-0], integ); } } break; case 9: { if(context == lex3) *ccharp++ = ELID; if(context == lex4) *ccharp++ = NILRET; /* return empty result */ } break; case 10: { if(context == lex4) invert(yyval, yypvt[-0]); } break; case 11: { yyval = ccharp; switch(context) { case lex2: name(yypvt[-1], DF); break; case lex3: name(yypvt[-0], ARG2); name(yypvt[-2], ARG1); break; case lex4: name(yypvt[-2], REST); name(yypvt[-0], REST); } } break; case 12: { yyval = ccharp; switch(context) { case lex2: name(yypvt[-1], MF); break; case lex3: name(yypvt[-0], ARG1); break; case lex4: name(yypvt[-0], REST); } } break; case 13: { if(context == lex2) name(yyval, NF); yyval = ccharp; } break; case 14: { yyval = yypvt[-0]; switch(context) { case lex3: name(yypvt[-1], AUTO); break; case lex4: integ = name(yypvt[-1], REST); invert(yyval, integ); } } break; case 15: { yyval = ccharp; } break; case 16: { litflag = -1; } break; case 18: { name(yypvt[-0], NAME); } break; case 20: { integ = ccharp[-1]; if(integ != ASGN && integ != PRINT && integ != COMNT) *ccharp++ = PRINT; } break; case 21: { yyval = ccharp; *ccharp++ = BRAN0; } break; case 22: { yyval = yypvt[-1]; *ccharp++ = BRAN; } break; case 24: { litflag = 1; yyval = ccharp; *ccharp++ = COMNT; } break; case 28: { *ccharp++ = PRINT; } break; case 30: { *ccharp++ = HPRINT; } break; case 32: { invert(yyval, yypvt[-0]); } break; case 33: { invert(yyval, yypvt[-0]); } break; case 35: { invert(yyval, yypvt[-1]); *ccharp++ = INDEX; *ccharp++ = scount; scount = yypvt[-2]; } break; case 36: { yyval = name(yyval, FUN); } break; case 37: { yyval = name(yyval, NAME); } break; case 38: { yyval = ccharp; ccharp =+ 2; integ = iline[-1]; vcount = 0; for(;;) { if(*iline == '\n') { nlexsym = unk; break; } if(*iline == integ) { iline++; break; } *ccharp++ = *iline++; vcount++; } yyval->c[0] = QUOT; yyval->c[1] = vcount; } break; case 39: { *ccharp++ = CONST; *ccharp++ = vcount; invert(yyval, ccharp-2); } break; case 40: { yyval = yypvt[-1]; } break; case 41: { yyval = ccharp; *ccharp++ = yypvt[-0]; } break; case 42: { vcount++; } break; case 43: { vcount = 1; } break; case 44: { yyval = ccharp; for(integ=0; integcsr&OFFLINE)) u.u_error = EACCES; else { cr.flags = OPEN; cr.blen = 0; } } crclose() { cr.flags = 0; } crstart() { register char *p; register int i; cr.bp = cr.card; cr.flags =& ~ERROR; CRADDR->csr =| GO; sleep(&cr, CRPRI); cr.blen = 81; p = &cr.card[80]; while(*p-- == 0) /* trim trailing blanks */ cr.blen--; } crread() { register i, k; register char *p; crstart(); if(cr.flags & ERROR){ u.u_error = EIO; return; } if(cr.card[0] == EOFCHAR) return; k = min(u.u_count, cr.blen); p = cr.card; for(i=0; idb2; if(CRADDR->csr & ERRORS) cr.flags =| ERROR; if(CRADDR->csr&DONE) wakeup(&cr); } q q?"4/purdue/sys/dmr/dh.c# /* */ /* * DH-11 driver * This driver calls on the DHDM driver. * If the DH has no DM11-BB, then the latter will * be fake. To insure loading of the correct DM code, * lib2 should have dhdm.o, dh.o and dhfdm.o in that order. */ #include "../param.h" #include "../conf.h" #include "../user.h" #include "../tty.h" #include "../proc.h" #define NDH11 4 /* number of DH11's (16 lines ea) */ #define DHNCH 16 /* max number of DMA chars */ struct tty dh11[NDH11*16]; #ifdef EP int ep[]; /* this is really a struct in ep.c */ #endif /* * addresses of DH11 CSR's, see also /usr/sys/conf/low.s */ int dhtab[] {0160020, 0160040, 0160060, 0160100, 0}; /* * Place from which to do DMA on output */ char dh_clist[NDH11*16][DHNCH]; /* * Used to communicate the number of lines to the DM */ int ndh11 NDH11*16; /* * Hardware control bits */ #define BITS6 01 #define BITS7 02 #define BITS8 03 #define TWOSB 04 #define PENABLE 020 /* DEC manuals incorrectly say this bit causes generation of even parity. */ #define OPAR 040 #define HDUPLX 040000 #define IENABLE 030100 #define PERROR 010000 #define FRERROR 020000 #define XINT 0100000 #define SSPEED 9 /* standard speed: 1200 baud */ /* * Software copy of last dhbar */ int dhsar[NDH11]; int dhint 0; /* nz if dh rcv interrupt routine active */ int dhprs 0; /* nz if dh once-only code already done */ struct dhregs { int dhcsr; int dhnxch; int dhlpr; int dhcar; int dhbcr; int dhbar; int dhbreak; int dhsilo; }; /* * Open a DH11 line. */ dhopen(dev, flag) { register struct tty *tp; extern dhstart(); extern dhsilock(); if(dhprs == 0) { dhprs++; /* once only code to start dhsilock */ timeout(&dhsilock,0,4); } if (dev.d_minor >= NDH11*16) { u.u_error = ENXIO; return; } tp = &dh11[dev.d_minor]; #ifdef XSTTY if(tp->t_speeds&(BLITZ|DRSVD)) { u.u_error = ENXIO; return; } #endif tp->t_addr = dhstart; tp->t_dev = dev; dhtab[(dev>>4)&017]->dhcsr =| IENABLE; tp->t_state =| WOPEN|SSTART; if ((tp->t_state&ISOPEN) == 0) { tp->t_erase = CERASE; tp->t_kill = CKILL; #ifndef XSTTY tp->t_speeds = SSPEED | (SSPEED<<8); #endif #ifdef XSTTY tp->t_speeds = SSPEED; /* extra flags are currently zeroed */ #endif tp->t_flags = ODDP|EVENP|ECHO|XTABS|LCASE|CRMOD; dhparam(tp); } dmopen(dev); tp->t_state =& ~WOPEN; tp->t_state =| ISOPEN; if (u.u_procp->p_ttyp == 0) u.u_procp->p_ttyp = tp; } /* * Allows DH11 to use silo buffering (32 chars) to reduce * the interrupt overhead during computer-computer xmissions * but still provide adequate keyboard service. * -ghg 11/18/76 */ dhsilock() { register int *dhp, *dhaddr; if(!dhint) { dhp = dhtab; while(dhaddr = *dhp++) if(dhaddr->dhsilo.hibyte&077) dhaddr->dhsilo = 0; /* cause interrupt */ } timeout(&dhsilock,0,4); /* recall self after 67 millisec */ } /* * Close a DH11 line. */ dhclose(dev) { register struct tty *tp; tp = &dh11[dev.d_minor]; #ifdef PUMP. tp->t_speed =& ~TOEOB; #endif dmclose(dev); wflushtty(tp); #ifdef XSTTY tp->t_speeds =& ~BLITZ; #endif tp->t_state =& (CARR_ON|SSTART); wakeup(&tp->t_speed); /* for other devices trying to reserve this one */ } /* * Read from a DH11 line. */ dhread(dev) { ttread(&dh11[dev.d_minor]); } /* * write on a DH11 line */ dhwrite(dev) { ttwrite(&dh11[dev.d_minor]); } /* * DH11 receiver interrupt. */ dhrint(dev) { register struct tty *tp; register int c; register int *dhaddr; dhint++; /* set rcv interrupt active */ dev =& 017; dhaddr = dhtab[dev]; while ((c = dhaddr->dhnxch) < 0) { /* char. present */ tp = &dh11[((c>>8)&017 | (dev<<4))]; if (tp >= &dh11[NDH11*16]) continue; #ifdef XSTTY /* hook for pump and other high speed stuff */ if(tp->t_xxpar) { if (sufet(c, tp->t_xxpar, tp->t_xxoff) || (c&FRERROR)) if((tp->t_speed&PUMP) == 0) /* buff overrun */ psignal(tp->t_xxpid, SIGHUP); c =& 0377; if((c == (tp->t_erase&0377)) && (tp->t_speeds&PUMP)) { if(tp->t_xxpid->p_pri > 0) tp->t_xxpid->p_pri = 1; psignal(tp->t_xxpid, tp->t_kill); } continue; } #endif if((tp->t_state&ISOPEN)==0 || (c&PERROR)) { wakeup(tp); continue; } if (c&FRERROR) /* break */ if (tp->t_flags&RAW) c = 0; /* null (for getty) */ else c = 0177; /* DEL (intr) */ ttyinput(c, tp); } dhaddr->dhsilo = 32; dhint = 0; } /* * stty/gtty for DH11 */ dhsgtty(dev, av) int *av; { register struct tty *tp; register r; tp = &dh11[dev.d_minor]; if (ttystty(tp, av)) return; dhparam(tp); } #ifndef XSTTY /* * Set parameters from open or stty into the DH hardware * registers. */ dhparam(atp) struct tty *atp; { register struct tty *tp; register int lpr; int *dhaddr; tp = atp; dhaddr = dhtab[(tp->t_dev>>4)&017]; spl5(); dhaddr->dhcsr.lobyte = tp->t_dev.d_minor&017 | IENABLE; /* * Hang up line? */ if (tp->t_speeds.lobyte==0) { tp->t_flags =| HUPCL; dmclose(tp->t_dev); return; } lpr = (tp->t_speeds.hibyte<<10) | (tp->t_speeds.lobyte<<6); /* if (tp->t_speeds.lobyte == 4) */ /* 134.5 baud */ /* for jgm and tgi lpr =| BITS6|PENABLE|HDUPLX; else */ if (tp->t_flags&EVENP) if (tp->t_flags&ODDP) lpr =| BITS8; else lpr =| BITS7|PENABLE; else lpr =| BITS7|OPAR|PENABLE; /* tmp klg for 6800 loading if (tp->t_speeds.lobyte == 3) 110 baud */ lpr =| TWOSB; dhaddr->dhlpr = lpr; spl0(); } #endif #ifdef XSTTY /* * Set parameters from open or stty into the DH hardware * registers. */ dhparam(atp) struct tty *atp; { register struct tty *tp; register int lpr; int *dhaddr; tp = atp; dhaddr = dhtab[(tp->t_dev>>4)&017]; spl5(); dhaddr->dhcsr.lobyte = tp->t_dev.d_minor&017 | IENABLE; /* * Hang up line? */ if ((tp->t_speeds&SPEED) == 0) { tp->t_flags =| HUPCL; dmclose(tp->t_dev); return; } lpr = ((tp->t_speeds&SPEED)<<6); lpr =| lpr << 4; /* if ((tp->t_speeds&SPEED) == 4) */ /* 134.5 baud */ /* for jgm and tgi lpr =| BITS6|PENABLE|HDUPLX; else */ if (tp->t_flags&EVENP) if (tp->t_flags&ODDP) lpr =| BITS8; else lpr =| BITS7|PENABLE; else lpr =| BITS7|OPAR|PENABLE; /* tmp klg for 6800 loading if ((tp->t_speeds&SPEED) == 3) 110 baud */ lpr =| TWOSB; dhaddr->dhlpr = lpr; spl0(); } #endif /* * DH11 transmitter interrupt. * Restart each line which used to be active but has * terminated transmission since the last interrupt. */ dhxint(dev) { register struct tty *tp; register ttybit, bar; int *dhaddr; dev =& 017; dhaddr = dhtab[dev]; bar = dhsar[dev] & ~dhaddr->dhbar; dhaddr->dhcsr =& ~XINT; ttybit = 1; tp = dh11; for (tp =+ (dev<<4); bar; tp++) { if(bar&ttybit) { dhsar[dev] =& ~ttybit; bar =& ~ttybit; tp->t_state =& ~BUSY; #ifndef EP dhstart(tp); #endif #ifdef EP /* if running with Electrostatic printer driver */ if(tp->t_speed&EPRNTR) epstart(tp); else dhstart(tp); #endif } ttybit =<< 1; } } /* * Start (restart) transmission on the given DH11 line. */ dhstart(atp) struct tty *atp; { extern ttrstrt(); register c, nch; register struct tty *tp; int sps; int dhunit; int *dhaddr; char *cp; sps = PS->integ; spl5(); tp = atp; /* * If it's currently active, or delaying, * no need to do anything. */ if (tp->t_state&(TIMEOUT|BUSY)) goto out; /* * t_char is a delay indicator which may have been * left over from the last start. * Arrange for the delay. */ if (c = tp->t_char) { tp->t_char = 0; if((c&0377) == 0376) /* suspend output, NL3 */ tp->t_state =| (TIMEOUT|HOLD); else { timeout(ttrstrt, tp, (c&0177)+6); tp->t_state =| TIMEOUT; } goto out; } cp = dh_clist[tp->t_dev.d_minor]; nch = 0; /* * Copy DHNCH characters, or up to a delay indicator, * to the DMA area. */ while (nch > -DHNCH && (c = getc(&tp->t_outq))>=0) { if(((tp->t_flags&RAW) ==0) && (c >= 0200)) { tp->t_char = c; break; } if((tp->t_flags&RAW) == 0) c =| 0200; /* 6500 needs parity bit on */ *cp++ = c; nch--; } /* * If the writer was sleeping on output overflow, * wake him when low tide is reached. */ if (tp->t_outq.c_cc<=TTLOWAT && tp->t_state&ASLEEP) { tp->t_state =& ~ASLEEP; wakeup(&tp->t_outq); } /* * If any characters were set up, start transmission; * otherwise, check for possible delay. */ if (nch) { dhunit = (tp->t_dev>>4)&017; dhaddr = dhtab[dhunit]; dhaddr->dhcsr.lobyte = tp->t_dev.d_minor&017 | IENABLE; dhaddr->dhcar = cp+nch; dhaddr->dhbcr = nch; c = 1<<(tp->t_dev.d_minor&017); dhaddr->dhbar =| c; dhsar[dhunit] =| c; tp->t_state =| BUSY; } else if (c = tp->t_char) { tp->t_char = 0; if((c&0377) == 0376) /* nl3, suspend output */ tp->t_state =| (TIMEOUT|HOLD); else { timeout(ttrstrt, tp, (c&0177)+6); tp->t_state =| TIMEOUT; } } out: PS->integ = sps; } nq 0q4/purdue/sys/dmr/mem.cc# /* */ /* * Memory special file * minor device 0 is physical memory * minor device 1 is kernel memory * minor device 2 is EOF/RATHOLE * minor device 3 is errorlog output */ #include "../param.h" #include "../user.h" #include "../conf.h" #include "../seg.h" #include "../errlog.h" mmread(dev) { register c, bn, on; int a, d; if(dev.d_minor == 2) return; if(dev.d_minor == 3) { while(!errlog.cc) sleep(&errlog, ERLPRI); while(errlog.cc && passc(c=getc(&errlog)) >= 0) if(c == '\n') return; return; } do { bn = lshift(u.u_offset, -6); on = u.u_offset[1] & 077; a = UISA->r[0]; d = UISD->r[0]; spl7(); UISA->r[0] = bn; UISD->r[0] = 077406; if(dev.d_minor == 1) UISA->r[0] = (ka6-6)->r[(bn>>7)&07] + (bn & 0177); c = fuibyte(on); UISA->r[0] = a; UISD->r[0] = d; spl0(); } while(u.u_error==0 && passc(c)>=0); } mmwrite(dev) { register c, bn, on; int a, d; if(dev.d_minor == 3) return; if(dev.d_minor == 2) { c = u.u_count; u.u_count = 0; u.u_base =+ c; dpadd(u.u_offset, c); return; } for(;;) { bn = lshift(u.u_offset, -6); on = u.u_offset[1] & 077; if ((c=cpass())<0 || u.u_error!=0) break; a = UISA->r[0]; d = UISD->r[0]; spl7(); UISA->r[0] = bn; UISD->r[0] = 077406; if(dev.d_minor == 1) UISA->r[0] = (ka6-6)->r[(bn>>7)&07] + (bn & 0177); suibyte(on, c); UISA->r[0] = a; UISD->r[0] = d; spl0(); } } q qP4/purdue/sys/dmr/tc.c# /* */ /* * TC-11 DECtape driver */ #include "../param.h" #include "../conf.h" #include "../buf.h" #include "../user.h" #include "../errlog.h" struct { int tccsr; int tccm; int tcwc; int tcba; int tcdt; }; struct devtab tctab; char tcper[8]; char tcopnf[8]; /* nz if unit is open */ int tcdbg; /* nz for debug mode or maint */ int tctick -1; /* >=0 timer running, <0 for not active */ int tcabtf; /* nz for drive hung, abort chain ahead */ #define TCTIMEOUT 10 /* abort drive if function not finished (sec) */ #define TCADDR 0177340 #define NTCBLK 578 #define TAPERR 0100000 #define TREV 04000 #define READY 0200 #define IENABLE 0100 #define UPS 0200 #define ENDZ 0100000 #define PAR 040000 #define MTE 020000 #define BLKM 02000 #define DATM 01000 #define NEXM 0400 #define ILGOP 010000 #define SELERR 04000 #define SAT 0 #define RNUM 02 #define RDATA 04 #define SST 010 #define WDATA 014 #define GO 01 #define SFORW 1 #define SREV 2 #define SIO 3 tcopen(dev) { extern tcck(); register int i; i = dev&07; if(tcopnf[i]) { u.u_error = ENXIO; return; } tcopnf[i]++; if(tctick < 0) { tctick = 0; timeout(&tcck, 0, 60); /* start watchdog timer */ } } /* * tcck - check for hung drive and abort the current function * This isn't needed for regular Dectape drives, however Linc * tape drives made by Computer Operations (Dectape compatible) * will leave the computer thinking they are still in motion * (forward or reverse) if the tape motion is stopped by turning * the drive offline during a period of non data transfer (search) * The drive will detect a switch to offline if a data transfer * is in progress. * -ghg 7/16/77. */ tcck() { if(tctick < 0) return; else { if(tctab.d_active && (tctick++ >= TCTIMEOUT)) { tcabtf++; TCADDR->tccm = SAT|IENABLE|GO; } if(tctick++ == 32767) tctick = 0; timeout(&tcck, 0, 60); } } tcclose(dev) { bflush(dev); tcper[dev&07] = 0; tcopnf[dev&07] = 0; } tcstrategy(abp) struct buf *abp; { register struct buf *bp; bp = abp; if(bp->b_flags&B_PHYS) mapalloc(bp); if(bp->b_blkno >= NTCBLK || tcper[bp->b_dev&07]) { bp->b_flags =| B_ERROR; iodone(bp); return; } bp->av_forw = 0; spl6(); if (tctab.d_actf==0) tctab.d_actf = bp; else tctab.d_actl->av_forw = bp; tctab.d_actl = bp; if (tctab.d_active==0) tcstart(); spl0(); } tcstart() { register struct buf *bp; register int *tccmp, com; loop: tccmp = &TCADDR->tccm; if ((bp = tctab.d_actf) == 0) return; if(tcper[bp->b_dev&07]) { if((tctab.d_actf = bp->av_forw) == 0) (*tccmp).lobyte = SAT|GO; bp->b_flags =| B_ERROR; iodone(bp); goto loop; } if (((*tccmp).hibyte&07) != bp->b_dev.d_minor) (*tccmp).lobyte = SAT|GO; tctab.d_errcnt = 20; tctab.d_active = SFORW; com = (bp->b_dev.d_minor<<8) | IENABLE|RNUM|GO; if ((TCADDR->tccsr & UPS) == 0) { com =| TREV; tctab.d_active = SREV; } tctick = 0; /* start timeout */ *tccmp = com; } tcintr() { register struct buf *bp; register int *tccmp; register int *tcdtp; tccmp = &TCADDR->tccm; tcdtp = &TCADDR->tccsr; if((bp = tctab.d_actf) == 0) return; tctick = 0; if(tcabtf) { tcabtf = 0; errlg++; printf("DECTAPE Hung - function aborted, BN=%d\n", bp->b_blkno); errlg = 0; goto err; } if (*tccmp&TAPERR) { if((*tcdtp & (PAR|MTE|DATM|NEXM)) || tcdbg) { errlg++; /* send printf to errlog device */ printf("DECTAPE ERR - st%o cm%o wc%o ba%o dt%o bn%d rt%d\n", *tcdtp, *tccmp, TCADDR->tcwc, TCADDR->tcba, TCADDR->tcdt, bp->b_blkno, tctab.d_errcnt); errlg = 0; } if(*tcdtp & (ILGOP|SELERR)) { err: tcper[bp->b_dev&07]++; tctab.d_errcnt = 0; *tccmp =& ~TAPERR; bp->b_flags =| B_ERROR; goto done; /* no deverror on SEL or Writlock err */ } *tccmp =& ~TAPERR; if (--tctab.d_errcnt <= 0) { errlg++; deverror(bp,*tcdtp,*tccmp); errlg = 0; bp->b_flags =| B_ERROR; goto done; } if (*tccmp&TREV) { setforw: tctab.d_active = SFORW; *tccmp =& ~TREV; } else { setback: tctab.d_active = SREV; *tccmp =| TREV; } (*tccmp).lobyte = IENABLE|RNUM|GO; return; } tcdtp = &TCADDR->tcdt; switch (tctab.d_active) { case SIO: done: tctab.d_active = 0; if (tctab.d_actf = bp->av_forw) tcstart(); else TCADDR->tccm.lobyte = SAT|GO; iodone(bp); return; case SFORW: if (*tcdtp > bp->b_blkno) goto setback; if (*tcdtp < bp->b_blkno) goto setforw; *--tcdtp = bp->b_addr; /* core address */ *--tcdtp = bp->b_wcount; tccmp->lobyte = ((bp->b_xmem & 03) << 4) | IENABLE|GO | (bp->b_flags&B_READ?RDATA:WDATA); tctab.d_active = SIO; return; case SREV: if (*tcdtp+3 > bp->b_blkno) goto setback; goto setforw; } } q Nq4/purdue/sys/dmr/tm.c# /* * TM tape driver * mods by j.b., winter and spring '76 */ #include "/usr/sys/param.h" #include "/usr/sys/buf.h" #include "/usr/sys/conf.h" #include "/usr/sys/user.h" struct { int tmer; int tmcs; int tmbc; int tmba; int tmdb; int tmrd; }; #define TMADDR 0172520 struct devtab tmtab; struct buf rtmbuf; #define GO 01 #define RCOM 02 #define WCOM 04 #define WEOF 06 #define SFORW 010 #define SREV 012 #define WIRG 014 #define REW 016 #define UNLOAD 000 #define IENABLE 0100 #define CRDY 0200 #define SELR 0100 #define WLOCK 0004 #define GAPSD 010000 #define BOT 040 #define EOT 04000 #define TUR 1 #define HARD 0100200 /* ILC, NXM */ #define PROG 0003000 /* EOT, RLE */ #define PARITY 0034400 /* PAE, CRE, BGL, BTE, */ #define EOF 0040000 /* EOF */ #define SSEEK 1 #define SIO 2 #define SKIPR 3 #define SKIPF 4 #define N_RETRY 15 /*page */ #define KDENS 066000 #define D 0160000 #define NINE 010000 #define CLREW 0100000 char t_openf[8]; char *t_blkno[8]; char *t_nxrec[8]; int tmlast[8]; /* last status */ int tmd[8] {D|NINE,D,D|NINE,D,D,D,D,D}; tmopen(dev, flag) { register dminor; dminor = dev.d_minor; if (t_openf[dminor] || !tu_online(dminor,flag)) u.u_error = ENXIO; else { t_openf[dminor]++; t_blkno[dminor] = 0; t_nxrec[dminor] = 65535; } } tmclose(dev, flag) { register int dminor; dminor = dev.d_minor; t_openf[dminor] = 0; if (flag) tcommand(dminor, WEOF); if(tmd[dminor]&CLREW) tcommand(dminor,REW,0); } tcommand(unit, com, count) { extern lbolt; while (tmtab.d_active || (TMADDR->tmcs & CRDY)==0) sleep(&lbolt, 1); TMADDR->tmbc = -count; TMADDR->tmcs = (tmd[unit]&KDENS)|com|GO | (unit<<8); } /*page */ tmstrategy(abp) struct buf *abp; { register struct buf *bp; register char **p; bp = abp; p = &t_nxrec[bp->b_dev.d_minor]; if (*p <= bp->b_blkno) { if (*p < bp->b_blkno) { bp->b_flags =| B_ERROR; iodone(bp); return; } if (bp->b_flags&B_READ) { clrbuf(bp); iodone(bp); return; } } if ((bp->b_flags&B_READ)==0) *p = bp->b_blkno + 1; bp->av_forw = 0; spl5(); if (tmtab.d_actf==0) tmtab.d_actf = bp; else tmtab.d_actl->av_forw = bp; tmtab.d_actl = bp; if (tmtab.d_active==0) tmstart(); spl0(); } /*page */ tmstart() { register struct buf *bp; register int com; int unit; register char *blkno; loop: if ((bp = tmtab.d_actf) == 0) return; unit = bp->b_dev.d_minor; blkno = t_blkno[unit]; if (t_openf[unit] < 0 || (TMADDR->tmcs & CRDY)==0 ) { bad: bp->b_flags =| B_ERROR; tmtab.d_actf = bp->av_forw; iodone(bp); goto loop; } com = (unit<<8) | ((bp->b_xmem & 03) << 4) | IENABLE|(tmd[unit]&KDENS); if(bp == &rtmbuf){ if((rtmbuf.b_flags&B_PHYS)==0){ com =| bp->b_addr; if((bp->b_addr == SREV && tmlast[unit]&BOT) || (bp->b_addr==SFORW && tmlast[unit]&EOT)) goto bad; tmtab.d_active = SIO; TMADDR->tmbc = bp->b_wcount; TMADDR->tmcs = com|GO; return; } } if (blkno != bp->b_blkno) { tmtab.d_active = SSEEK; if (blkno < bp->b_blkno) { com =| SFORW|GO; TMADDR->tmbc = blkno - bp->b_blkno; } else { if (bp->b_blkno == 0 && bp != &rtmbuf) com =| REW|GO; else { com =| SREV|GO; TMADDR->tmbc = bp->b_blkno - blkno; } } TMADDR->tmcs = com; return; } tmtab.d_active = SIO; TMADDR->tmbc = bp->b_wcount << 1; TMADDR->tmba = bp->b_addr; TMADDR->tmcs = com | ((bp->b_flags&B_READ)? RCOM|GO: ((tmtab.d_errcnt)? WIRG|GO: WCOM|GO)); } /*page */ tmintr() { register struct buf *bp; register int unit, *pp; if ((bp = tmtab.d_actf)==0) return; unit = bp->b_dev.d_minor; tmlast[unit] = TMADDR->tmer; if(TMADDR->tmcs < 0) { while(TMADDR->tmrd&GAPSD) {} if(TMADDR->tmer&HARD) goto hard; if(TMADDR->tmer&PROG) goto prog; if(TMADDR->tmer&EOF) if(bp == &rtmbuf){ if(bp->b_flags&B_READ) TMADDR->tmbc = bp->b_wcount*2; goto next; } else goto eof; if(TMADDR->tmer&PARITY && tmtab.d_active == SIO) { if(++tmtab.d_errcnt < N_RETRY) { t_blkno[unit]++; goto retry; } goto prog; /* retry count exhausted */ } goto prog; /* error on skip */ printf("\n\"impossible\" mag-tape error:\n"); hard: /* hard(ware) error --irrecoverable */ deverror(bp,TMADDR->tmer,TMADDR->tmcs); eof: /* illegal EOF */ t_openf[unit] = -1; /* stop all subsequent i/o */ prog: /* programmer or irrecoverable parity err */ bp->b_flags =| B_ERROR; /* mark buffer bad */ tmtab.d_active = SIO; /* so it'll get iodone */ } /* end of error handler */ next: if (tmtab.d_active == SIO) { tmtab.d_errcnt = 0; t_blkno[unit]++; tmtab.d_actf = bp->av_forw; tmtab.d_active = 0; bp->b_resid = TMADDR->tmbc; iodone(bp); } else t_blkno[unit] = bp->b_blkno; retry: tmstart(); } /*page */ tmread(dev) { tmsetup(dev); physio(tmstrategy, &rtmbuf, dev, B_READ); /* if(rtmbuf.b_flags&EOF==0) */ u.u_count = -rtmbuf.b_resid; } tmwrite(dev) { if(u.u_count == 0) tcommand(dev.d_minor,WEOF,0); else { tmsetup(dev); physio(tmstrategy, &rtmbuf, dev, B_WRITE); u.u_count = 0; } } tmsetup(dev) { register unit, a; unit = dev.d_minor; a = lshift(u.u_offset, -9); t_blkno[unit] = a; t_nxrec[unit] = ++a; u.u_count =+ u.u_count&01; /* odd to even */ } tu_online(unit,flag) { extern lbolt; while(tmtab.d_active || (TMADDR->tmcs&CRDY)==0) sleep(&lbolt,1); TMADDR->tmcs = unit<<8; if(TMADDR->tmer & SELR) if(!flag) return(1); else return(TMADDR->tmer&WLOCK ? 0 : 1); else return(0); } /*page */ #define PEVEN 04000 #define DEN556 0 #define DEN800 020000 #define DEN800D 040000 #define DEN1600 060000 #define BPI1600 02000 #define DENSITY 060000 #define CLREW 0100000 #define NINE 010000 #define DENDIF 020000 #define UMASK (DENSITY|PEVEN|CLREW|NINE) #define SMASK (UMASK|BPI1600) tmsgtty(dev,av) int dev,*av; { register int *v,unit,x; unit = dev.d_minor; if(v=av) { /* getty */ *v++ = (tmd[unit]&UMASK) - (tmd[unit]&BPI1600? 0: DENDIF); *v++ = 0; *v++ = 0; } else { /* setty */ v = u.u_arg; if(*v & 0377) { u.u_error = tmxcom(dev,v); } else { x = *v; if((tmd[unit]&NINE) == NINE){ if((x&DENSITY) < DEN800D) goto fail; x =| NINE; } if((x & DENSITY) == DEN1600 ) if((tmd[unit]&NINE)==NINE) x =| BPI1600; else goto fail; else x =+ DENDIF; tmd[unit] = x & SMASK; } } return; fail: u.u_error = EINVAL; } /*page */ tmxcom(dev,av) int *av; { register int *v,count,com; int error; v = av; count = v[1]; switch(*v&0377){ default: /* undefined operation */ return(EINVAL); case 1: /* endfile */ com = WEOF; break; case 2: /* skip files forward */ error = 0; while(count-- > 0 && (error&EOT) == 0) error = tmphys(&rtmbuf,dev,SFORW,0100000); return(0); /* * case 3 is coded differently from the seemingly symmetrical * case 2, because of the peculiar behavior of the DIGI-DATA * tape drives near the BOT. * God save us from whatever perils lurk beyond the EOT. */ case 3: /* skip files backward */ error = 0; count++; while(count-- > 0 && (error&BOT) == 0){ error = tmphys(&rtmbuf,dev,SREV,200); if((error&EOF) == 0) count++; } com = SREV; goto out; case 4: /* skip records forward */ com = SFORW; break; case 5: /* skip records backward */ com = SREV; if(count > 512) count = 512; break; case 6: /* rewind */ com = REW; break; case 7: /* rewind & unload */ com = UNLOAD; break; } error = tmphys(&rtmbuf,dev,com,count); out: if((error&EOF) && com == SREV) error = tmphys(&rtmbuf,dev,SFORW,1); return(0); } /*page */ tmphys(abp,dev,com,count) struct buf *abp; { register struct buf *bp; bp = abp; spl6(); while(bp->b_flags&B_BUSY){ bp->b_flags =| B_WANTED; sleep(bp,PRIBIO); } bp->b_flags =| B_BUSY; bp->b_flags =& ~(B_PHYS | B_DONE); bp->b_dev = dev; bp->b_wcount = -count; bp->b_addr = com; bp->b_xmem = 0; tmstrategy(bp); spl6(); while((bp->b_flags&B_DONE)==0) sleep(bp,PRIBIO); if(bp->b_flags&B_WANTED) wakeup(bp); bp->b_flags =& ~(B_BUSY | B_WANTED); spl0(); geterror(bp); return(tmlast[dev.d_minor]&(BOT|EOT|EOF)); } sq fq94/purdue/sys/dmr/tty.cc# /* */ /* * general TTY subroutines */ #include "../param.h" #include "../systm.h" #include "../user.h" #include "../tty.h" #include "../proc.h" #include "../inode.h" #include "../file.h" #include "../reg.h" #include "../conf.h" #include "../errlog.h" /* * Input mapping table-- if an entry is non-zero, when the * corresponding character is typed preceded by "\" the escape * sequence is replaced by the table value. Mostly used for * upper-case only terminals. */ char maptab[] { 000,000,000,000,004,000,000,000, 000,000,000,000,000,000,000,000, 000,000,000,000,000,000,000,000, 000,000,000,000,000,000,000,000, 000,'|',000,'#',000,000,000,'`', '{','}',000,000,000,000,000,000, 000,000,000,000,000,000,000,000, 000,000,000,000,000,000,000,000, '@',000,000,000,000,000,000,000, 000,000,000,000,000,000,000,000, 000,000,000,000,000,000,000,000, 000,000,000,000,000,000,'~',000, 000,'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',000,000,000,000,000, }; /* * The actual structure of a clist block manipulated by * getc and putc (mch.s) */ struct cblock { struct cblock *c_next; char info[6]; }; /* The character lists-- space for 6*NCLIST characters */ struct cblock cfree[NCLIST]; /* List head for unused character blocks. */ struct cblock *cfreelist; /* * structure of device registers for KL, DL, and DC * interfaces-- more particularly, those for which the * SSTART bit is off and can be treated by general routines * (that is, not DH). */ struct { int ttrcsr; int ttrbuf; int tttcsr; int tttbuf; }; /* * The routine implementing the gtty system call. * Just call lower level routine and pass back values. */ gtty() { int v[3]; register *up, *vp; vp = v; sgtty(vp); if (u.u_error) return; up = u.u_arg[0]; suword(up, *vp++); suword(++up, *vp++); suword(++up, *vp++); } /* * The routine implementing the stty system call. * Read in values and call lower level. */ stty() { register int *up; up = u.u_arg[0]; u.u_arg[0] = fuword(up); u.u_arg[1] = fuword(++up); u.u_arg[2] = fuword(++up); sgtty(0); } /* * Stuff common to stty and gtty. * Check legality and switch out to individual * device routine. * v is 0 for stty; the parameters are taken from u.u_arg[]. * c is non-zero for gtty and is the place in which the device * routines place their information. */ sgtty(v) int *v; { register struct file *fp; register struct inode *ip; if ((fp = getf(u.u_ar0[R0])) == NULL) return; ip = fp->f_inode; if ((ip->i_mode&IFMT) != IFCHR) { u.u_error = ENOTTY; return; } (*cdevsw[ip->i_addr[0].d_major].d_sgtty)(ip->i_addr[0], v); } /* * Wait for output to drain, then flush input waiting. */ wflushtty(atp) struct tty *atp; { register struct tty *tp; tp = atp; spl5(); nohold: if(tp->t_state&HOLD) { tp->t_state =& ~(HOLD|TIMEOUT); ttrstrt(tp); } while (tp->t_outq.c_cc) { if(tp->t_state & HOLD) goto nohold; /* don't let suspend hang close */ tp->t_state =| ASLEEP; sleep(&tp->t_outq, TTOPRI); } flushtty(tp); spl0(); } /* * Initialize clist by freeing all character blocks, then count * number of character devices. (Once-only routine) */ cinit() { register int ccp; register struct cblock *cp; register struct cdevsw *cdp; ccp = cfree; for (cp=(ccp+07)&~07; cp <= &cfree[NCLIST-1]; cp++) { cp->c_next = cfreelist; cfreelist = cp; } ccp = 0; for(cdp = cdevsw; cdp->d_open; cdp++) ccp++; nchrdev = ccp; } /* * flush all TTY queues */ flushtty(atp) struct tty *atp; { register struct tty *tp; register int sps; tp = atp; while (getc(&tp->t_canq) >= 0); while (getc(&tp->t_outq) >= 0); wakeup(&tp->t_rawq); wakeup(&tp->t_outq); sps = PS->integ; spl5(); while (getc(&tp->t_rawq) >= 0); tp->t_delct = 0; tp->t_state =& ~(TIMEOUT|HOLD); PS->integ = sps; } /* * transfer raw input list to canonical list, * doing erase-kill processing and handling escapes. * It waits until a full line has been typed in cooked mode, * or until any character has been typed in raw mode. */ canon(atp) struct tty *atp; { register char *bp; char *bp1; register struct tty *tp; register int c; tp = atp; spl5(); while (tp->t_delct==0) { #ifdef XSTTY if(tp->t_speeds&BLITZ) return(0); #endif /* if ((tp->t_state&CARR_ON)==0) return(0); */ sleep(&tp->t_rawq, TTIPRI); } spl0(); loop: bp = &canonb[2]; while ((c=getc(&tp->t_rawq)) >= 0) { if (c==0377) { tp->t_delct--; break; } if ((tp->t_flags&RAW)==0) { if (bp[-1]!='\\') { if (c==tp->t_erase) { if (bp > &canonb[2]) bp--; continue; } if (c==tp->t_kill) goto loop; if (c==CEOT) continue; } else if (maptab[c] && (maptab[c]==c || (tp->t_flags&LCASE))) { if (bp[-2] != '\\') c = maptab[c]; bp--; } } *bp++ = c; if (bp>=canonb+CANBSIZ) break; } bp1 = bp; bp = &canonb[2]; c = &tp->t_canq; while (bpt_flags; if (((c =& 0177) == '\r' || c == 037 ) && t_flags&CRMOD) c = '\n'; if ((t_flags&RAW)==0 && (c==CQUIT || c==CINTR)) { signal(tp, c==CINTR? SIGINT:SIGQIT); flushtty(tp); return; } if((t_flags&RAW)==0 && (c==CHOLD || c==CACK)) { if(tp->t_state&HOLD) { tp->t_state =& ~HOLD; ttrstrt(tp); } else tp->t_state =| (TIMEOUT|HOLD); return; } #ifdef XSTTY if(c==021 || (tp->t_speed&SUSNL) == 0) if(tp->t_state&HOLD) { tp->t_state =& ~HOLD; ttrstrt(tp); } /* temp kludge to make enad file xfer work. if nl3 & 021 received */ /* then 021 is tossed out and output suspend is cleared */ if(c==021 && (tp->t_speed&SUSNL)) return; /* ......................................................*/ #endif if (tp->t_rawq.c_cc>=TTYHOG) { flushtty(tp); return; } if (t_flags&LCASE && c>='A' && c<='Z') c =+ 'a'-'A'; if(cblkct >= NCLIST-20) { flushtty(tp); /* printf("ttyi clist overrun dev = %d/%d\n", tp->t_dev.d_major, tp->t_dev.d_minor); */ return; } putc(c, &tp->t_rawq); if (t_flags&RAW || c=='\n' || c==004 || c==021) { wakeup(&tp->t_rawq); if (putc(0377, &tp->t_rawq)==0) tp->t_delct++; } if(( c == tp->t_kill) && ((tp->t_flags&RAW) == 0)) { ttyoutput('x',tp); ttyoutput('x',tp); ttyoutput('x',tp); ttyoutput('\n',tp); ttstart(tp); return; } if (t_flags&ECHO) { if(c == tp->t_erase) switch((tp->t_flags>>10)&03) { case 3: ttyoutput('\010',tp); ttyoutput('\040',tp); c = '\010'; break; case 2: ; case 1: ; case 0: ; } ttyoutput(c, tp); ttstart(tp); } } /* * put character on TTY output queue, adding delays, * expanding tabs, and handling the CR/NL bit. * It is called both from the top half for output, and from * interrupt level for echoing. * The arguments are the character and the tty structure. */ ttyoutput(ac, tp) struct tty *tp; { register int c; register struct tty *rtp; register char *colp; int ctype; extern int cblkct; /* count of cblocks in use (putc/m45.s) */ rtp = tp; c = ac; /* * If clist almost full - blast this guy -ghg 10/14/77 */ if(cblkct >= NCLIST-20) { flushtty(rtp); /* printf("ttyo clist overrun dev = %d/%d\n", rtp->t_dev.d_major, rtp->t_dev.d_minor); */ } /* * Turn tabs to spaces as required */ if ((c&0177)=='\t' && rtp->t_flags&XTABS) { do ttyoutput(' ', rtp); while (rtp->t_col&07); return; } /* * for upper-case-only terminals, * generate escapes. */ if (rtp->t_flags&LCASE) { c =& 0177; colp = "({)}!|^~'`"; while(*colp++) if(c == *colp++) { ttyoutput('\\', rtp); c = colp[-2]; break; } if ('a'<=c && c<='z') c =+ 'A' - 'a'; } /* * display control characters if desired */ if(rtp->t_flags<0){ c =& 0177; ctype = partab[c]; if((ctype&077) == 1 && c != 007 ) { ttyoutput('^',rtp); c =| 0100; } } /* * turn to if desired. */ if ((c&0177)=='\n' && rtp->t_flags&CRMOD) ttyoutput('\r', rtp); /* * Ignore EOT in normal mode to avoid hanging up * certain terminals. */ if((rtp->t_flags&RAW)==0) { c =& 0177; if(c==CEOT) return; } else { putc(c, &rtp->t_outq); #ifdef PUMP. if(rtp->t_speed&PUMP) return; #endif rtp->t_col++; if(c == '\n') rtp->t_col = 0; return; } if (putc(c, &rtp->t_outq)) return; /* * Calculate delays. * The numbers here represent clock ticks * and are not necessarily optimal for all terminals. * The delays are indicated by characters above 0200, * thus (unfortunately) restricting the transmission * path to 7 bits. */ colp = &rtp->t_col; ctype = partab[c]; c = 0; switch (ctype&077) { /* ordinary */ case 0: (*colp)++; /* non-printing */ case 1: break; /* backspace */ case 2: if (*colp) (*colp)--; break; /* newline */ case 3: ctype = (rtp->t_flags >> 8) & 03; if(ctype == 1) { /* tty 37 */ if (*colp) c = max((*colp>>4) + 3, 6); } else if(ctype == 2) { /* vt05 */ c = 6; } else if(ctype == 3) /* suspend output, CDC1700 */ c = 0176; *colp = 0; break; /* tab */ case 4: ctype = (rtp->t_flags >> 10) & 03; if(ctype == 1) { /* tty 37 */ c = 1 - (*colp | ~07); if(c < 5) c = 0; } *colp =| 07; (*colp)++; break; /* vertical motion */ case 5: if(rtp->t_flags & VTDELAY) /* tty 37 */ c = 0177; break; /* carriage return */ case 6: ctype = (rtp->t_flags >> 12) & 03; if(ctype == 1) { /* tn 300 */ c = 5; } else if(ctype == 2) { /* ti 700 */ c = 10; } *colp = 0; } if(c) putc(c|0200, &rtp->t_outq); } /* * 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. */ ttrstrt(atp) { register struct tty *tp; tp = atp; if(tp->t_state&HOLD) return; tp->t_state =& ~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. * If the SSTART bit is off for the tty the work is done here, * using the protocol of the single-line interfaces (KL, DL, DC); * otherwise the address word of the tty structure is * taken to be the name of the device-dependent startup routine. */ ttstart(atp) struct tty *atp; { register int *addr, c; register struct tty *tp; struct { int (*func)(); }; tp = atp; addr = tp->t_addr; if (tp->t_state&SSTART) { (*addr.func)(tp); return; } if ((addr->tttcsr&DONE)==0 || tp->t_state&TIMEOUT) return; if ((c=getc(&tp->t_outq)) >= 0) { if(tp->t_flags&RAW) { addr->tttbuf = c; return; } if (c<=0177) addr->tttbuf = c | (partab[c]&0200); else { if((c&0377) == 0376) /*suspend output */ tp->t_state =| (HOLD|TIMEOUT); else { timeout(ttrstrt, tp, c&0177); tp->t_state =| TIMEOUT; } } } } /* * Called from device's read routine after it has * calculated the tty-structure given as argument. * The pc is backed up for the duration of this call. * In case of a caught interrupt, an RTI will re-execute. */ ttread(atp) struct tty *atp; { register struct tty *tp; register char c; tp = atp; #ifdef XSTTY if(tp->t_speeds&BLITZ) return; #endif /* if ((tp->t_state&CARR_ON)==0) return; */ c = 0; if (tp->t_canq.c_cc || canon(tp)) #ifdef XSTTY while (tp->t_canq.c_cc && passc((c=getc(&tp->t_canq)))>=0) if(tp->t_speed & SPY) { errlg++; putchar(c); c = errlg = 0; } if(c) if(tp->t_speed & SPY) { errlg++; putchar(c); errlg = 0; } #endif #ifndef XSTTY while (tp->t_canq.c_cc && passc((getc(&tp->t_canq)))>=0); #endif } /* * Called from the device's write routine after it has * calculated the tty-structure given as argument. */ ttwrite(atp) struct tty *atp; { register struct tty *tp; register int c; tp = atp; #ifdef XSTTY if(tp->t_speeds&BLITZ) return; #ifdef PUMP. if(tp->t_speeds&PUMP) tp->t_col = 0; #endif #endif /* if ((tp->t_state&CARR_ON)==0) return; */ while ((c=cpass())>=0) { spl5(); while (tp->t_outq.c_cc > TTHIWAT) { ttstart(tp); tp->t_state =| ASLEEP; #ifdef PUMP. if(tp->t_speeds&PUMP) sleep(&tp->t_outq, PUMPRI); else sleep(&tp->t_outq, TTOPRI); #endif #ifndef PUMP. sleep(&tp->t_outq, TTOPRI); #endif } spl0(); ttyoutput(c, tp); #ifdef XSTTY if (tp->t_speed & SPY) { errlg++; putchar(c); errlg = 0; } #endif } ttstart(tp); } /* * Common code for gtty and stty functions on typewriters. * If v is non-zero then gtty is being done and information is * passed back therein; * if it is zero stty is being done and the input information is in the * u_arg array. */ ttystty(atp, av) int *atp, *av; { register *tp, *v; #ifdef PUMP. extern pumpck(); #endif tp = atp; if(v = av) { #ifdef XSTTY *v++ = tp->t_speeds& ~SPY; #endif #ifndef XSTTY *v++ = tp->t_speeds; #endif v->lobyte = tp->t_erase; v->hibyte = tp->t_kill; v[1] = tp->t_flags; return(1); } v = u.u_arg; #ifdef XSTTY if(*v & SPY) { if(u.u_uid) return(1); tp->t_speeds =^ SPY; return(1); } *v =| tp->t_speed&SPY; /* preserve spy bit */ if(*v&BLITZ) flushtty(tp); else wflushtty(tp); tp->t_speeds = *v++; /* Don't allow users to set following bits (su only) */ if(u.u_uid) tp->t_speeds =& ~(PUMP|TOEOB|TIMACT|DRSVD); #ifdef PUMP. spl6(); if((tp->t_speeds&(TOEOB|TIMACT)) == TOEOB) { tp->t_speeds =| TIMACT; tp->t_col = 0; timeout(&pumpck, tp, 60); } spl0(); #endif #endif #ifndef XSTTY wflushtty(tp); tp->t_speeds = *v++; #endif tp->t_erase = v->lobyte; tp->t_kill = v->hibyte; tp->t_flags = v[1]; return(0); } #ifdef PUMP. /* * Routine to send PUMP end of block (rubout) incase the user mode * PUMP process gets tied up waiting for disk I/O to complete for * over 2 seconds. This keeps the line from going out of sync. * Warning: This code uses t_col for a scratch counter. If this * port is running in PUMP mode, then nobody else should use t_col. * --ghg 10/09/77 */ pumpck(atp) { register struct tty *tp; tp = atp; if((tp->t_speeds&TOEOB) == 0) { tp->t_speeds =& ~TIMACT; return; } timeout(&pumpck, tp, 60); if(tp->t_outq.c_cc) goto out; if(++tp->t_col == 2) { putc(0377, &tp->t_outq); ttstart(tp); goto out; } return; out: tp->t_col = 0; } #endif nqeͷq4/purdue/sys/errlog.h# /* * errorlog - to handle internal printf's for non critical areas * * -ghg 07/04/77 */ #define MAXERL 600 /* maximum numb of chars to put on clist */ #define ERLPRI 2 /* priority for errlog sleep */ int errlg; /* if set nz, errlog will be used instead */ /* if internal (without interrupts) print */ struct errlog { int cc; /* clist pointers for errlog */ int cf; int cl; } errlog; q|A\4/purdue/sys/kenoq{q 4/purdue/sys/ken/prf.cc# /* */ #include "../param.h" #include "../seg.h" #include "../buf.h" #include "../conf.h" #include "../systm.h" #include "../errlog.h" /* * Address and structure of the * KL-11 console device registers. */ struct { int rsr; int rbr; int xsr; int xbr; }; /* * In case console is off, * panicstr contains argument to last * call to panic. */ char *panicstr; /* * Scaled down version of C Library printf. * Only %s %l %d (==%l) %o are recognized. * Used to print diagnostic information * directly on console tty. * Since it is not interrupt driven, * all system activities are pretty much * suspended. * Printf should not be used for chit-chat. * * If the system variable errlg is non zero, characters will be * stuffed on the clist instead of being printed on the console * with interrupts off. The errlog minor dev (in mem.c) sucks * the characters back out and gives them to a user job to * print them out. This avoids hanging the system for things * like magtape and other non system device errors. Critical * errors (like panics) will still print on the console. It * is the device driver's responsibility to set and clear "errlg". * -ghg 07/04/77 */ printf(fmt,x1,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc) char fmt[]; { register char *s; register *adx, c; int p; adx = &x1; loop: while((c = *fmt++) != '%') { if(c == '\0') return; putchar(c); } p = 0; while((c = *fmt++) >= '0' && c <= '9') p = p*10 + c - '0'; if(c == 'd' || c == 'l' || c == 'o') printn(*adx, c=='o'? 8: 10, p); if(c == 's') { s = *adx; while(c = *s++) putchar(c); } if(c == 'c') putchar(*adx); adx++; goto loop; } /* * Print an unsigned integer in base b. */ printn(n, b, p) { register a; if((a = ldiv(n, b)) != 0 || p > 1) printn(a, b, p-1); putchar(lrem(n, b) + '0'); } /* * Print a character on console. * Attempts to save and restore device * status. */ putchar(c) { register rc, s; static int crflg,t[3]; if((rc = c) == 0) return; if(crflg){ crflg = 0; prtime(t); printf("%2d:%2d:%2d ",t[0],t[1],t[2]); } if(errlg) { if(errlog.cc >= MAXERL) return; putc(rc, &errlog); if(rc == '\n') { wakeup(&errlog); crflg++; } } else { while((KL->xsr&0200) == 0) {} s = KL->xsr; KL->xsr = 0; KL->xbr = rc; if(rc == '\n') { putchar('\r'); putchar(0177); putchar(0177); crflg++; } KL->xsr = s; } } /* * Panic is called on unresolvable * fatal errors. * It syncs, prints "panic: mesg" and * then loops. */ panic(s) char *s; { errlg = 0; /* force message to console */ panicstr = s; update(); printf("panic: %s\n", s); for(;;) idle(); } /* * prdev prints a warning message of the * form "mesg on dev x/y". * x and y are the major and minor parts of * the device argument. */ prdev(str, dev) { printf("\n%s on dev %l/%l\n", str, dev.d_major, dev.d_minor); } /* * deverr prints a diagnostic from * a device driver. * It prints the device, block number, * and an octal word (usually some error * status register) passed as argument. */ deverror(bp, o1, o2) int *bp; { register *rbp,a,x; rbp = bp; prdev("err", rbp->b_dev); printf("block# 0%l err 0%o 0%o", rbp->b_blkno, o1, o2); x = rbp->b_xmem&03; x =<< 1; a = rbp->b_addr; x =+ (a < 0 ? 1 : 0); a =& 077777; printf(" addr: %o%5o (18)\n",x,a); } \qfqV4/purdue/sys/ken/prtime.s.globl _prtime _prtime: jsr r5,csv mov _time,r0 /get current time mov _time+2,r1 sub $18000.,r1 /convert GMT to EST sbc r0 div $28800.,r0 /break sec. into sec + 8-hr chunks mov r0,r2 /save 8-hr chunks clr r0 div $60.,r0 /get seconds mov r1,seconds mov r0,r1 clr r0 div $60.,r0 /get min mov r1,min mov r0,hours /r0 = hours (mod 8) clr r0 mov r2,r1 / get hr*8 div $3,r0 mul $8.,r1 / convert to hours add r1,hours mov 4(r5),r0 mov hours,(r0)+ mov min,(r0)+ mov seconds,(r0)+ jmp cret fmt: <%d:%d:%d. \0> .bss hours: . = .+2 min: . = .+2 seconds:. = .+2 .text q q4/purdue/sys/l.sp/ low core XSWAP = 1 / run with primary and sec swap devs br4 = 200 br5 = 240 br6 = 300 br7 = 340 . = 0^. br 1f 4 / trap vectors trap; br7+0. / bus error trap; br7+1. / illegal instruction trap; br7+2. / bpt-trace trap trap; br7+3. / iot trap pfail; br7+4. / power fail trap; br7+5. / emulator trap trap; br7+6. / system entry . = 40^. .globl start, dump 1: jmp start jmp dump . = 50^. .globl _proc _proc . = 52^. /last char read from diagnostic tty port .globl _diagc _diagc: 0 . = 60^. klin; br4 klou; br4 . = 70^. pcin; br4 pcou; br4 . = 100^. kwlp; br6 kwlp; br6 . = 114^. trap; br7+7. / 11/70 parity . = 124^. daio; br5+0. / DA-11 DMA unibus link (DR-11b) /////////////////////////////////////////////////////////////// / UNIX low core pointers and variables / / vector space between 150 and 200 is currently unused by dec/ / -ghg 1/1/77 / /////////////////////////////////////////////////////////////// .globl _rootdev, _swapdev, _swplo, _nswap, _stsp . = 150^. / start of system pointers _rootdev: .byte 0.,6. / major + minor of rootdev (6/0 hp0) . = 152^. _swapdev: .byte 0.,1. / major + minor dev of swap dev (1/0 sw) . = 154^. _swplo: 1. / first block of swap area (can't be 0) . = 156^. _nswap: 8489. / number of blocks in swap area / _rootdev to _nswap were moved from "/usr/sys/conf/conf.c" / to low core so they can be patched at boot up time / incase of a hardware failure of the root/swap devices. / After boot-up, the cpu should be halted just after the 22-bit / (18-bit if 11/45) addressing light comes on. The locations / should be patched up with the front panel switches and the / cpu continued. .if XSWAP .globl _pswapdev, _sswapdev, _pswplo, _sswplo, _paddrx, _ptimx . = 160^. _pswapdev: .byte 8.,5. /* primary swap (5/8 hs0) _sswapdev: .byte 6,6 / sec swap (6/6 hp6) _pswplo: 1500. /start of primary swap (cant be 0) _sswplo: 1 /start of sec swap (can't be 0) _paddrx: 547. /first logical swap addr on sec swap dev _ptimx: 45. /idle time before staged to sec swp .endif . = 174^. .globl _pipedev _pipedev: .byte 8.,5. / pipe device . = 176^. _stsp: 0 / pointer to system statistics block //////////////////////////////////////////////////////////////////// / end of UNIX low core pointers and variables / //////////////////////////////////////////////////////////////////// . = 200^. lpou; br5 . = 204^. hsio; br5 . = 214^. / DEC tapes tcio; br6 . = 224^. htio; br5 . = 240^. trap; br7+7. / programmed interrupt trap; br7+8. / floating point trap; br7+9. / segmentation violation . = 254^. hpio; br5 / floating vectors . = 300^. emin; br4+0. / DM11-BB #0 (serviced by ep handler) . = 304^. emin; br4+1. / DM11-BB #1 (serviced by ep handler) . = 310^. emin; br4+2. / DM11-BB #2 (serviced by ep handler) . = 320^. /1st dh-11 dhin; br5+0. / DH11-0 receive int dhou; br5+0. / DH11-0 xmit int . = 330^. /2nd dh-11 dhin; br5+1. / DH11-1 receive interrupt dhou; br5+1. / DH11-1 xmit interrupt . = 340^. /3rd dh-11 dhin; br5+2. / DH11-2 receive int dhou; br5+2. / DH11-2 xmit int . = 350^. /4th dh-11 dhin; br5+3. / DH11-3 receive int dhou; br5+3. / DH11-3 xmit int ////////////////////////////////////////////////////// / interface code to C ////////////////////////////////////////////////////// .globl call, trap .globl _klrint klin: jsr r0,call; _klrint .globl _klxint klou: jsr r0,call; _klxint .globl _pcrint pcin: jsr r0,call; _pcrint .globl _pcpint pcou: jsr r0,call; _pcpint .globl _clock kwlp: jsr r0,call; _clock .globl _lpint lpou: jsr r0,call; _lpint .globl _hsintr hsio: jsr r0,call; _hsintr .globl _htintr htio: jsr r0,call; _htintr .globl _hpintr hpio: jsr r0,call; _hpintr .globl _dhrint dhin: jsr r0,call; _dhrint .globl _dhxint dhou: jsr r0,call; _dhxint .globl _tcintr tcio: jsr r0,call; _tcintr .globl _emintr /Regular DM11-BB handler not used (no dialup) emin: jsr r0,call; _emintr .globl _daintr daio: jsr r0,call; _daintr pfail: /Power failure - print crash message reset clr r0 /wait awhile sob r0,. clr r0 sob r0,. clr r0 sob r0,. reset=5 halt=0 csxsr=177564 csbuf=177566 /Decwriter console address mov $pfm,r0 /address of power fail message pf1: tstb csxsr /wait for DL-11 to go ready bpl pf1 /not ready yet movb (r0)+,csbuf /stuff character to DL-11 bne pf1 halt br pfail pfm: <> / let decwriter warm up <\r\n\r\n PANIC CRASH! - Power Fail - Reboot and recover\r\n\0> .even q ḗq/4/purdue/sys/m45.st/ machine language assist / for 11/45 or 11/70 CPUs .fpp = 1 / .pump = 1 / hooks for pump / non-UNIX instructions mfpi = 6500^tst mtpi = 6600^tst mfpd = 106500^tst mtpd = 106600^tst spl = 230 ldfps = 170100^tst stfps = 170200^tst wait = 1 halt = 0 rtt = 6 reset = 5 HIPRI = 300 HIGH = 6 / Mag tape dump / save registers in low core and / write all core onto mag tape. / entry is thru 44 abs .data .globl dump dump: bit $1,SSR0 bne dump / save regs r0,r1,r2,r3,r4,r5,r6,KIA6 / starting at abs location 4 mov r0,4 mov $6,r0 mov r1,(r0)+ mov r2,(r0)+ mov r3,(r0)+ mov r4,(r0)+ mov r5,(r0)+ mov sp,(r0)+ mov KDSA6,(r0)+ / dump all of core (ie to first mt error) / onto mag tape. (9 track or 7 track 'binary') / this code is for TU16 magtape, 9 track drive -ghg 11/17/76 mov $MTC,r0 clr 4(r0) /zero buss address mov $1300,32(r0) /set 800 bpi odd parity 1: mov $-256.,2(r0) /set 256 word write mov $-512.,6(r0) /set byte count movb $61,(r0) /start write 2: tstb 12(r0) /wait for drdy in mtds bpl 2b bit $40000,(r0) /error, probably nexm beq 1b /no, get more reset mov $27,(r0) /write end of file br . /hang .globl start, _end, _edata, _etext, _main / 11/45 and 11/70 startup. / entry is thru 0 abs. / since core is shuffled, / this code can be executed but once start: inc $-1 bne . reset clr PS / set KI0 to physical 0 mov $77406,r3 mov $KISA0,r0 mov $KISD0,r1 clr (r0)+ mov r3,(r1)+ / set KI1-6 to eventual text resting place mov $_end+63.,r2 ash $-6,r2 bic $!1777,r2 1: mov r2,(r0)+ mov r3,(r1)+ add $200,r2 cmp r0,$KISA7 blos 1b / set KI7 to IO seg for escape mov $IO,-(r0) / set KD0-7 to physical mov $KDSA0,r0 mov $KDSD0,r1 clr r2 1: mov r2,(r0)+ mov r3,(r1)+ add $200,r2 cmp r0,$KDSA7 blos 1b / initialization / get a temp (1-word) stack / turn on segmentation / copy text to I space / clear bss in D space mov $stk+2,sp mov $65,SSR3 / 22-bit, map, K+U sep bit $20,SSR3 beq 1f mov $70.,_cputype 1: inc SSR0 mov $_etext,r0 mov $_edata,r1 add $_etext-8192.,r1 1: mov -(r1),-(sp) mtpi -(r0) cmp r1,$_edata bhi 1b 1: clr (r1)+ cmp r1,$_end blo 1b / use KI escape to set KD7 to IO seg / set KD6 to first available core mov $IO,-(sp) mtpi *$KDSA7 mov $_etext-8192.+63.,r2 ash $-6,r2 bic $!1777,r2 add KISA1,r2 mov r2,KDSA6 / set up supervisor D registers mov $6,SISD0 mov $6,SISD1 / set up real sp / clear user block mov $_u+[usize*64.],sp mov $_u,r0 1: clr (r0)+ cmp r0,sp blo 1b / jsr pc,_isprof / set up previous mode and call main / on return, enter user mode at 0R mov $30000,PS jsr pc,_main mov $170000,-(sp) clr -(sp) rtt .globl trap, call .globl _trap / all traps and interrupts are / vectored thru this routine. trap: mov PS,saveps tst nofault bne 1f mov SSR0,ssr mov SSR1,ssr+2 mov SSR2,ssr+4 mov $1,SSR0 jsr r0,call1; _trap / no return 1: mov $1,SSR0 mov nofault,(sp) rtt .text .globl _runrun, _swtch call1: mov saveps,-(sp) spl 0 br 1f call: mov PS,-(sp) 1: mov r1,-(sp) mfpd sp mov 4(sp),-(sp) bic $!37,(sp) bit $30000,PS beq 1f .if .fpp mov $20,_u+4 / FP maint mode .endif jsr pc,*(r0)+ 2: spl HIGH tstb _runrun beq 2f spl 0 jsr pc,_savfp jsr pc,_swtch br 2b 2: .if .fpp mov $_u+4,r1 bit $20,(r1) bne 2f mov (r1)+,r0 ldfps r0 movf (r1)+,fr0 movf (r1)+,fr1 movf fr1,fr4 movf (r1)+,fr1 movf fr1,fr5 movf (r1)+,fr1 movf (r1)+,fr2 movf (r1)+,fr3 ldfps r0 2: .endif tst (sp)+ mtpd sp br 2f 1: bis $30000,PS jsr pc,*(r0)+ cmp (sp)+,(sp)+ 2: mov (sp)+,r1 tst (sp)+ mov (sp)+,r0 rtt .globl _savfp _savfp: .if .fpp mov $_u+4,r1 bit $20,(r1) beq 1f stfps (r1)+ movf fr0,(r1)+ movf fr4,fr0 movf fr0,(r1)+ movf fr5,fr0 movf fr0,(r1)+ movf fr1,(r1)+ movf fr2,(r1)+ movf fr3,(r1)+ 1: .endif rts pc .globl _incupc _incupc: mov r2,-(sp) mov 6(sp),r2 / base of prof with base,leng,off,scale mov 4(sp),r0 / pc sub 4(r2),r0 / offset clc ror r0 mul 6(r2),r0 / scale ashc $-14.,r0 inc r1 bic $1,r1 cmp r1,2(r2) / length bhis 1f add (r2),r1 / base mov nofault,-(sp) mov $2f,nofault mfpd (r1) inc (sp) mtpd (r1) br 3f 2: clr 6(r2) 3: mov (sp)+,nofault 1: mov (sp)+,r2 rts pc .globl _display _display: dec dispdly bge 2f clr dispdly mov PS,-(sp) mov $HIPRI,PS mov CSW,r1 bit $1,r1 beq 1f bis $30000,PS dec r1 1: jsr pc,fuword mov r0,CSW mov (sp)+,PS cmp r0,$-1 bne 2f mov $120.,dispdly / 2 sec delay after CSW fault 2: rts pc / Character list get/put .globl _getc, _putc .globl _cfreelist .globl _ccount .globl _cblkct _getc: mov PS,-(sp) spl 6 mov 4(sp),r1 mov r2,-(sp) mov 2(r1),r2 / first ptr beq 9f / empty movb (r2)+,r0 / character bic $!377,r0 mov r2,2(r1) dec (r1)+ / count bne 1f clr (r1)+ clr (r1)+ / last block br 2f 1: bit $7,r2 bne 3f mov -10(r2),(r1) / next block add $2,(r1) 2: dec r2 bic $7,r2 mov _cfreelist,(r2) mov r2,_cfreelist / stats -ghg dec _cblkct /...................... 3: / statistics code -ghg dec _ccount / ................ mov (sp)+,r2 mov (sp)+,PS rts pc 9: clr 4(r1) mov $-1,r0 mov (sp)+,r2 mov (sp)+,PS rts pc _putc: mov PS,-(sp) spl 6 mov 4(sp),r0 mov 6(sp),r1 mov r2,-(sp) mov r3,-(sp) mov 4(r1),r2 / last ptr bne 1f mov _cfreelist,r2 beq 9f mov (r2),_cfreelist / statistics -ghg inc _cblkct / .................................. clr (r2)+ mov r2,2(r1) / first ptr br 2f 1: bit $7,r2 bne 2f mov _cfreelist,r3 beq 9f mov (r3),_cfreelist / stats -ghg inc _cblkct / ............................... mov r3,-10(r2) mov r3,r2 clr (r2)+ 2: movb r0,(r2)+ mov r2,4(r1) inc (r1) / count / statistics -ghg inc _ccount / count of active chars in clist / ................... clr r0 mov (sp)+,r3 mov (sp)+,r2 mov (sp)+,PS rts pc 9: mov pc,r0 mov (sp)+,r3 mov (sp)+,r2 mov (sp)+,PS rts pc .globl _backup .globl _regloc _backup: mov 2(sp),r0 movb ssr+2,r1 jsr pc,1f movb ssr+3,r1 jsr pc,1f movb _regloc+7,r1 asl r1 add r0,r1 mov ssr+4,(r1) clr r0 2: rts pc 1: mov r1,-(sp) asr (sp) asr (sp) asr (sp) bic $!7,r1 movb _regloc(r1),r1 asl r1 add r0,r1 sub (sp)+,(r1) rts pc .globl _fubyte, _subyte .globl _fuword, _suword .globl _fuibyte, _suibyte .globl _fuiword, _suiword _fuibyte: mov 2(sp),r1 bic $1,r1 jsr pc,giword br 2f _fubyte: mov 2(sp),r1 bic $1,r1 jsr pc,gword 2: cmp r1,2(sp) beq 1f swab r0 1: bic $!377,r0 rts pc _suibyte: mov 2(sp),r1 bic $1,r1 jsr pc,giword mov r0,-(sp) cmp r1,4(sp) beq 1f movb 6(sp),1(sp) br 2f 1: movb 6(sp),(sp) 2: mov (sp)+,r0 jsr pc,piword clr r0 rts pc _subyte: mov 2(sp),r1 bic $1,r1 jsr pc,gword mov r0,-(sp) cmp r1,4(sp) beq 1f movb 6(sp),1(sp) br 2f 1: movb 6(sp),(sp) 2: mov (sp)+,r0 jsr pc,pword clr r0 rts pc _fuiword: mov 2(sp),r1 fuiword: jsr pc,giword rts pc _fuword: mov 2(sp),r1 fuword: jsr pc,gword rts pc giword: mov PS,-(sp) spl HIGH mov nofault,-(sp) mov $err,nofault mfpi (r1) mov (sp)+,r0 br 1f gword: mov PS,-(sp) spl HIGH mov nofault,-(sp) mov $err,nofault mfpd (r1) mov (sp)+,r0 br 1f _suiword: mov 2(sp),r1 mov 4(sp),r0 suiword: jsr pc,piword rts pc _suword: mov 2(sp),r1 mov 4(sp),r0 suword: jsr pc,pword rts pc piword: mov PS,-(sp) spl HIGH mov nofault,-(sp) mov $err,nofault mov r0,-(sp) mtpi (r1) br 1f pword: mov PS,-(sp) spl HIGH mov nofault,-(sp) mov $err,nofault mov r0,-(sp) mtpd (r1) 1: mov (sp)+,nofault mov (sp)+,PS rts pc err: mov (sp)+,nofault mov (sp)+,PS tst (sp)+ mov $-1,r0 rts pc .if .pump / support code for nonblocking read to user buffer at interrupt time .globl _sufet _sufet: mov 6(sp),r0 / fet offset from PAR add $20000,r0 / map through PAR 1 mov r0,r1 mov PS,-(sp) / must lock out all interrupts mov KDSA1,-(sp) / save Kernel I PAR 1 spl 7 mov 10(sp),KDSA1 / point PAR 1 to user buffer add (r0),r1 / r1 has addr of next input char inc (r0) / advance user buffer pointer (in) movb 6(sp),(r1) / store character cmp (r0)+,(r0) / check for buffer wrap around bne 2f / no wrap mov $6,-2(r0) / set in = start of buffer 2: cmp -(r0),4(r0) / return true if buffer overrun beq 3f clr r0 3: mov (sp)+,KDSA1 / restore Mem-Mgmnt PAR 1 mov (sp)+,PS rts pc .endif .globl _copyin, _copyout .globl _copyiin, _copyiout _copyiin: jsr pc,copsu 1: mfpi (r0)+ mov (sp)+,(r1)+ sob r2,1b br 2f _copyin: jsr pc,copsu 1: mfpd (r0)+ mov (sp)+,(r1)+ sob r2,1b br 2f _copyiout: jsr pc,copsu 1: mov (r0)+,-(sp) mtpi (r1)+ sob r2,1b br 2f _copyout: jsr pc,copsu 1: mov (r0)+,-(sp) mtpd (r1)+ sob r2,1b 2: mov (sp)+,nofault mov (sp)+,r2 clr r0 rts pc copsu: mov (sp)+,r0 mov r2,-(sp) mov nofault,-(sp) mov r0,-(sp) mov 10(sp),r0 mov 12(sp),r1 mov 14(sp),r2 asr r2 mov $1f,nofault rts pc 1: mov (sp)+,nofault mov (sp)+,r2 mov $-1,r0 rts pc .globl _idle _idle: mov PS,-(sp) spl 0 wait mov (sp)+,PS rts pc .globl _halt _halt: halt rts pc .globl _savu, _retu, _aretu _savu: spl HIGH mov (sp)+,r1 mov (sp),r0 mov sp,(r0)+ mov r5,(r0)+ spl 0 jmp (r1) _aretu: spl 7 mov (sp)+,r1 mov (sp),r0 br 1f _retu: spl 7 mov (sp)+,r1 mov (sp),KDSA6 mov $_u,r0 1: mov (r0)+,sp mov (r0)+,r5 spl 0 jmp (r1) .globl _spl0, _spl1, _spl4, _spl5, _spl6, _spl7 _spl0: spl 0 rts pc _spl1: spl 1 rts pc _spl4: spl 4 rts pc _spl5: spl 5 rts pc _spl6: spl 6 rts pc _spl7: spl HIGH rts pc .globl _copyseg _copyseg: mov PS,-(sp) mov 4(sp),SISA0 mov 6(sp),SISA1 mov $10000+HIPRI,PS mov r2,-(sp) clr r0 mov $8192.,r1 mov $32.,r2 1: mfpd (r0)+ mtpd (r1)+ sob r2,1b mov (sp)+,r2 mov (sp)+,PS rts pc .globl _clearseg _clearseg: mov PS,-(sp) mov 4(sp),SISA0 mov $10000+HIPRI,PS clr r0 mov $32.,r1 1: clr -(sp) mtpd (r0)+ sob r1,1b mov (sp)+,PS rts pc .globl _dpadd _dpadd: mov 2(sp),r0 add 4(sp),2(r0) adc (r0) rts pc .globl _dpcmp _dpcmp: mov 2(sp),r0 mov 4(sp),r1 sub 6(sp),r0 sub 8(sp),r1 sbc r0 bge 1f cmp r0,$-1 bne 2f cmp r1,$-512. bhi 3f 2: mov $-512.,r0 rts pc 1: bne 2f cmp r1,$512. blo 3f 2: mov $512.,r1 3: mov r1,r0 rts pc .globl _dpdiv _dpdiv: mov 2(sp),r0 mov 4(sp),r1 div 6(sp),r0 rts pc .globl _dprem _dprem: mov 2(sp),r0 mov 4(sp),r1 div 6(sp),r0 mov r1,r0 rts pc .globl _ldiv _ldiv: clr r0 mov 2(sp),r1 div 4(sp),r0 rts pc .globl _lrem _lrem: clr r0 mov 2(sp),r1 div 4(sp),r0 mov r1,r0 rts pc .globl _lshift _lshift: mov 2(sp),r1 mov (r1)+,r0 mov (r1),r1 ashc 4(sp),r0 mov r1,r0 rts pc .globl csv csv: mov r5,r0 mov sp,r5 mov r4,-(sp) mov r3,-(sp) mov r2,-(sp) jsr pc,(r0) .globl cret cret: mov r5,r1 mov -(r1),r4 mov -(r1),r3 mov -(r1),r2 mov r5,sp mov (sp)+,r5 rts pc .globl _u _u = 140000 usize = 16. CSW = 177570 PS = 177776 SSR0 = 177572 SSR1 = 177574 SSR2 = 177576 SSR3 = 172516 KISA0 = 172340 KISA1 = 172342 KISA7 = 172356 KISD0 = 172300 KDSA0 = 172360 KDSA1 = 172362 KDSA6 = 172374 KDSA7 = 172376 KDSD0 = 172320 MTC = 172440 /TU16 csr SISA0 = 172240 SISA1 = 172242 SISD0 = 172200 SISD1 = 172202 IO = 177600 .data .globl _ka6 .globl _cputype _ka6: KDSA6 _cputype:45. stk: 0 .bss .globl nofault, ssr nofault:.=.+2 ssr: .=.+6 dispdly:.=.+2 saveps: .=.+2 .text / system profiler / /rtt = 6 /CCSB = 172542 /CCSR = 172540 /PS = 177776 / /.globl _sprof, _xprobuf, _probuf, _probsiz, _mode /_probsiz = 7500.+2048. / /_isprof: / mov $_sprof,104 / interrupt / mov $340,106 / pri / mov $100.,CCSB / count set = 100 / mov $113,CCSR / count down, 10kHz, repeat / rts pc / /_sprof: / mov r0,-(sp) / mov PS,r0 / ash $-11.,r0 / bic $!14,r0 / add $1,_mode+2(r0) / adc _mode(r0) / cmp r0,$14 / user / beq done / mov 2(sp),r0 / pc / asr r0 / asr r0 / bic $140001,r0 / cmp r0,$_probsiz / blo 1f / inc _outside / br done /1: / inc _probuf(r0) / bne done / mov r1,-(sp) / mov $_xprobuf,r1 /2: / cmp (r1)+,r0 / bne 3f / inc (r1) / br 4f /3: / tst (r1)+ / bne 2b / sub $4,r1 / mov r0,(r1)+ / mov $1,(r1)+ /4: / mov (sp)+,r1 /done: / mov (sp)+,r0 / mov $113,CCSR / rtt / /.bss /_xprobuf: .=.+512. /_probuf:.=.+_probsiz /_mode: .=.+16. /_outside: .=.+2 $q q 4/purdue/sys/param.hm/* * system conditional compilation */ #define XSWAP /* run with 2 swap devices: pswapdev and sswapdev */ /* * tunable variables */ #define NBUF 40 /* size of buffer cache */ #define NINODE 225 /* number of in core inodes */ #define NFILE 200 /* number of in core file structures */ #define NMOUNT 9 /* number of mountable file systems */ #define NEXEC 4 /* number of simultaneous exec's */ #define NCARGS 10240 /* length of arg list for exec */ #define MAXMEM (64*32) /* max core per process - first # is Kw */ #define MAXBLK 2048 /* max size (in blks) of a non su file */ #define SSIZE 20 /* initial stack size (*64 bytes) */ #define SINCR 20 /* increment of stack (*64 bytes) */ #define NOFILE 15 /* max open files per process */ #define CANBSIZ 256 /* max size of typewriter line */ #define CMAPSIZ 300 /* size of core allocation area */ #define SMAPSIZ 300 /* size of swap allocation area */ #define NCALL 50 /* max simultaneous time callouts */ #define NPROC 150 /* max number of processes */ #define MAXJOB 20 /* max number of processes per user */ #define NTEXT 40 /* max number of pure texts */ #define NCLIST 600 /* max total clist size */ #define HZ 60 /* Ticks/second of the clock */ /* * priorities * probably should not be * altered too much */ #define PSWP -100 #define PINOD -90 #define PRIBIO -50 #define PFNT -3 /* wait for more file table space */ #define PPIPE 1 #define PWAIT 40 #define PSLEP 80 #define PUSER 90 /* * signals * dont change */ #define NSIG 20 #define SIGHUP 1 /* hangup */ #define SIGINT 2 /* interrupt (rubout) */ #define SIGQIT 3 /* quit (FS) */ #define SIGINS 4 /* illegal instruction */ #define SIGTRC 5 /* trace or breakpoint */ #define SIGIOT 6 /* iot */ #define SIGEMT 7 /* emt */ #define SIGFPT 8 /* floating exception */ #define SIGKIL 9 /* kill */ #define SIGBUS 10 /* bus error */ #define SIGSEG 11 /* segmentation violation */ #define SIGSYS 12 /* sys */ #define SIGPIPE 13 /* end of pipe */ /* * fundamental constants * cannot be changed */ #define USIZE 16 /* size of user block (*64) */ #define NULL 0 #define NODEV (-1) #define ROOTINO 1 /* i number of all roots */ #define DIRSIZ 14 /* max characters per directory */ /* * structure to access an * integer in bytes */ struct { char lobyte; char hibyte; }; /* * structure to access an integer */ struct { int integ; }; /* * Certain processor registers */ #define PS 0177776 #define KL 0177560 #define SW 0177570 q Gq 4/purdue/sys/systm.hm/* * Random set of variables * used by more than one * routine. */ char canonb[CANBSIZ]; /* buffer for erase and kill (#@) */ int coremap[CMAPSIZ]; /* space for core allocation */ int swapmap[SMAPSIZ]; /* space for swap allocation */ int *rootdir; /* pointer to inode of root directory */ int cputype; /* type of cpu =40, 45, or 70 */ int execnt; /* number of processes in exec */ int lbolt; /* time of day in 60th not in time */ int time[2]; /* time in sec from 1970 */ int tout[2]; /* time of day of next sleep */ /* * 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 teletypes. */ struct callo { int c_time; /* incremental time */ int c_arg; /* argument to routine */ int (*c_func)(); /* routine */ } callout[NCALL]; /* * Mount structure. * One allocated on every mount. * Used to find the super block. */ struct mount { int m_dev; /* device mounted */ int *m_bufp; /* pointer to superblock */ int *m_inodp; /* pointer to mounted on inode */ } mount[NMOUNT]; int mpid; /* generic for unique process id's */ char runin; /* scheduling flag */ char runout; /* scheduling flag */ char runrun; /* scheduling flag */ char curpri; /* more scheduling */ #ifdef XSWAP int runstg; /* nz if sched to stage out to sswapdev*/ int pswapdev; /* primary swap (see low.s) */ int sswapdev; /* sec swap dev (see low.s) */ int pswplo; /* first block to use on pswapdev */ int sswaplo; /* first block to use on sswapdev */ int ptimx; /* max time on pri swap dev */ int paddrx; /* end if pswap (see low.s) */ int npriswp; /* numb of primary swaps (for stats) */ int nsecswp; /* numb of secondary swaps (stats) */ int nstages; /* numb of stage outs from pri swap */ #endif int maxmem; /* actual max memory per process */ int maxblk; /* largest block of non su file, set in main.c */ int *lks; /* pointer to clock device */ int rootdev; /* dev of root see conf.c */ int pipedev; /* pipe dev (initialized in low.s) */ int swapdev; /* dev of swap see conf.c */ int swplo; /* block number of swap space */ int nswap; /* size of swap space */ int updlock; /* lock for sync */ int rablock; /* block to be read ahead */ char regloc[]; /* locs. of saved user registers (trap.c) */ /* System statistics block */ int ccount; /* count of characters currently on clist */ int cblkct; /* count of allocated blocks in clist */ q Pq=4/purdue/sys/tty.hh#define XSTTY /* use extended flag bits in speeds word */ #define EP /* run with ep handler (requires XSTTY to be defined) */ #define PUMP. /* PUMP support code in tty driver. (requires XSTTY) */ /* * A clist structure is the head * of a linked list queue of characters. * The characters are stored in 4-word * blocks containing a link and 6 characters. * The routines getc and putc (m45.s or m40.s) * manipulate these structures. */ struct clist { int c_cc; /* character count */ int c_cf; /* pointer to first block */ int c_cl; /* pointer to last block */ }; /* * A tty structure is needed for * each UNIX character device that * is used for normal terminal IO. * The routines in tty.c handle the * common code associated with * these structures. * The definition and device dependent * code is in each driver. (kl.c dc.c dh.c) */ struct tty { struct clist t_rawq; /* input chars right off device */ struct clist t_canq; /* input chars after erase and kill */ struct clist t_outq; /* output list to device */ int t_flags; /* mode, settable by stty call */ int *t_addr; /* device address (register or startup fcn) */ char t_delct; /* number of delimiters in raw q */ char t_col; /* printing column of device */ char t_erase; /* erase character */ char t_kill; /* kill character */ char t_state; /* internal state, not visible externally */ char t_char; /* character temporary */ int t_speeds; /* output+input line speed */ int t_dev; /* device name */ #ifdef XSTTY int t_xxpid; /* pid of job with xx device open */ int t_xxpar; /* if nz, contains PAR to map to user */ char t_xxoff; /* buf offset (0-77) for PAR mapping */ #endif }; char partab[]; /* ASCII table: parity, character class */ #define TTIPRI 10 #define TTOPRI 20 #define PUMPRI -1 /* must be negative */ #define CERASE '#' /* default special characters */ #define CEOT 004 #define CKILL '@' #define CQUIT 034 /* FS, cntl shift L */ #define CINTR 0177 /* DEL */ #define CHOLD 0033 /* ESC -- suspend output */ #define CACK 0006 /* ACK - currently same as suspend output */ /* limits */ #define TTHIWAT 200 #define TTLOWAT 120 #define TTYHOG 256 /* modes */ #define HUPCL 01 #define XTABS 02 #define LCASE 04 #define ECHO 010 #define CRMOD 020 #define RAW 040 #define ODDP 0100 #define EVENP 0200 #define NLDELAY 001400 #define TBDELAY 006000 #define CRDELAY 030000 #define VTDELAY 040000 #define BSDELAY 0100000 #ifdef XSTTY /* extra mode bits in high order 12 bits of speed word. * Note only 4 bits (3-0) are used to set speed, ispeed and * ospeed are both set to speed. * -ghg 7/4/77. */ #define SPEED 017 /* index into baud rate table */ #define DRSVD 020 /* device reserved by another handler */ #define TIMACT 040 /* PUMP EOB timer active */ #define TOEOB 0100 /* end of block timeout processing for PUMP */ #define SPY 0200 /* spy on this device (stty write only) */ #define PUMP 0400 /* special processing for PUMP */ #define SUSNL 01000 /* suspend output on newline output */ #define BLITZ 02000 /* blitz - abort all i/o until close */ #ifdef EP #define EPRNTR 04000 /* set if electrostic printer */ #endif #endif /* Hardware bits */ #define DONE 0200 #define IENABLE 0100 /* Internal state bits */ #define TIMEOUT 01 /* Delay timeout in progress */ #define WOPEN 02 /* Waiting for open to complete */ #define ISOPEN 04 /* Device is open */ #define SSTART 010 /* Has special start routine at addr */ #define CARR_ON 020 /* Software copy of carrier-present */ #define BUSY 040 /* Output in progress */ #define ASLEEP 0100 /* Wakeup when output done */ #define HOLD 0200 /* output suspended */ rqj A'4\4/pitteqi A64\͛4/pitt/11stuffyqh C4Ql*4/pitt/11stuff/MakefileCFLAGS=-O -I. o=clrerr.o data.o debug.o doprnt.o doscan.o fclose.o \ fdopen.o fdopensub.o fdup.o fget.o fgetc.o fgets.o filbuf.o fopen.o \ fopensub.o fperror.o fprintf.o fput.o fputc.o fputs.o freopen.o \ fsalloc.o fseek.o ftell.o fwipe.o getchar.o getgrent.o getgrgid.o \ getgrnam.o getpass.o getpw.o getpwent.o getpwnam.o getpwuid.o gets.o \ getw.o popen.o printf.o putchar.o puts.o putw.o rdwr.o rew.o \ scanf.o setbuf.o sprintf.o stdio.o strout.o system.o tmpnam.o \ makebuf.o ungetc.o cuexit.o fscratch.o libS.a : $o fltpr.o ffltpr.o gcvt.o ar cr libS.a `lorder $o | tsort` ar rb doprnt.o libS.a fltpr.o ar ra doprnt.o libS.a gcvt.o ffltpr.o clean : rm -f *.o cuexit.o : /usr/src/libc/gen/cuexit.s as -o cuexit.o /usr/src/libc/gen/cuexit.s .c.o : cc $(CFLAGS) -c $*.c .s.o : as -o $*.o $*.s qg @4MFB4/pitt/11stuff/compallcc -c -O /usr/src/libc/stdio/clrerr.c cc -c -O /usr/src/libc/stdio/data.c cc -c -O /usr/src/libc/stdio/debug.c cc -c -O /usr/src/libc/stdio/doscan.c cc -c -O /usr/src/libc/stdio/fclose.c cc -c -O /usr/src/libc/stdio/fdopen.c cc -c -O /usr/src/libc/stdio/fdopensub.c cc -c -O /usr/src/libc/stdio/fdup.c cc -c -O /usr/src/libc/stdio/fget.c cc -c -O /usr/src/libc/stdio/fgetc.c cc -c -O /usr/src/libc/stdio/fgets.c cc -c -O /usr/src/libc/stdio/filbuf.c cc -c -O /usr/src/libc/stdio/fopen.c cc -c -O /usr/src/libc/stdio/fopensub.c cc -c -O /usr/src/libc/stdio/fperror.c cc -c -O /usr/src/libc/stdio/fprintf.c cc -c -O /usr/src/libc/stdio/fput.c cc -c -O /usr/src/libc/stdio/fputc.c cc -c -O /usr/src/libc/stdio/fputs.c cc -c -O /usr/src/libc/stdio/freopen.c cc -c -O /usr/src/libc/stdio/fsalloc.c cc -c -O /usr/src/libc/stdio/fscratch.c cc -c -O /usr/src/libc/stdio/fseek.c cc -c -O /usr/src/libc/stdio/ftell.c cc -c -O /usr/src/libc/stdio/fwipe.c cc -c -O /usr/src/libc/stdio/gcvt.c cc -c -O /usr/src/libc/stdio/getchar.c cc -c -O /usr/src/libc/stdio/getgrent.c cc -c -O /usr/src/libc/stdio/getgrgid.c cc -c -O /usr/src/libc/stdio/getgrnam.c cc -c -O /usr/src/libc/stdio/getpass.c cc -c -O /usr/src/libc/stdio/getpw.c cc -c -O /usr/src/libc/stdio/getpwent.c cc -c -O /usr/src/libc/stdio/getpwnam.c cc -c -O /usr/src/libc/stdio/getpwuid.c cc -c -O /usr/src/libc/stdio/gets.c cc -c -O /usr/src/libc/stdio/getw.c cc -c -O /usr/src/libc/stdio/makebuf.c cc -c -O /usr/src/libc/stdio/popen.c cc -c -O /usr/src/libc/stdio/printf.c cc -c -O /usr/src/libc/stdio/putchar.c cc -c -O /usr/src/libc/stdio/puts.c cc -c -O /usr/src/libc/stdio/putw.c cc -c -O /usr/src/libc/stdio/rdwr.c cc -c -O /usr/src/libc/stdio/rew.c cc -c -O /usr/src/libc/stdio/scanf.c cc -c -O /usr/src/libc/stdio/setbuf.c cc -c -O /usr/src/libc/stdio/sprintf.c cc -c -O /usr/src/libc/stdio/stdio.c cc -c -O /usr/src/libc/stdio/strout.c cc -c -O /usr/src/libc/stdio/system.c cc -c -O /usr/src/libc/stdio/tmpnam.c cc -c -O /usr/src/libc/stdio/ungetc.c cc -c /usr/src/libc/stdio/fltpr.s cc -c /usr/src/libc/stdio/doprnt.s cc -c /usr/src/libc/stdio/ffltpr.s cc -c /usr/src/libc/gen/cuexit.s cc -c -O /usr/src/libc/gen/execvp.c cc -c -O /usr/src/libc/gen/getenv.c cc -c -O /usr/src/libc/gen/getlogin.c cc -c -O /usr/src/libc/gen/perror.c cc -c -O /usr/src/libc/gen/sleep.c cc -c -O /usr/src/libc/gen/timezone.c cc -c -O /usr/src/libc/gen/ttyslot.c cc -c -O /usr/src/libc/gen/ttyname.c cc -c /usr/src/libc/gen/abort.s cc -c -O /usr/src/libc/gen/abs.c cc -c -O /usr/src/libc/gen/atof.c cc -c -O /usr/src/libc/gen/atoi.c cc -c -O /usr/src/libc/gen/atol.c cc -c -O /usr/src/libc/gen/crypt.c cc -c -O /usr/src/libc/gen/ctime.c cc -c -O /usr/src/libc/gen/calloc.c cc -c -O /usr/src/libc/gen/malloc.c cc -c -O /usr/src/libc/gen/ecvt.c cc -c -O /usr/src/libc/gen/errlst.c cc -c /usr/src/libc/gen/fakcu.s cc -c /usr/src/libc/gen/fakfp.s cc -c /usr/src/libc/gen/frexp11.s cc -c -O /usr/src/libc/gen/isatty.c cc -c -O /usr/src/libc/gen/l3.c cc -c /usr/src/libc/gen/ldexp11.s cc -c /usr/src/libc/gen/ldfps.s cc -c -O /usr/src/libc/gen/mktemp.c cc -c /usr/src/libc/gen/modf11.s cc -c -O /usr/src/libc/gen/mpx.c cc -c -O /usr/src/libc/gen/mon.c cc -c -O /usr/src/libc/gen/nlist.c cc -c -O /usr/src/libc/gen/qsort.c cc -c -O /usr/src/libc/gen/rand.c cc -c /usr/src/libc/gen/setjmp.s cc -c -O /usr/src/libc/gen/stty.c cc -c -O /usr/src/libc/gen/swab.c cc -c -O /usr/src/libc/gen/tell.c cc -c -O /usr/src/libc/gen/ctype_.c cc -c -O /usr/src/libc/gen/index.c cc -c -O /usr/src/libc/gen/rindex.c cc -c -O /usr/src/libc/gen/strcat.c cc -c -O /usr/src/libc/gen/strncat.c cc -c -O /usr/src/libc/gen/strcmp.c cc -c -O /usr/src/libc/gen/strncmp.c cc -c -O /usr/src/libc/gen/strcpy.c cc -c -O /usr/src/libc/gen/strncpy.c cc -c -O /usr/src/libc/gen/strlen.c cc -c /usr/src/libc/sys/access.s cc -c /usr/src/libc/sys/acct.s cc -c /usr/src/libc/sys/alarm.s cc -c /usr/src/libc/sys/chdir.s cc -c /usr/src/libc/sys/chroot.s cc -c /usr/src/libc/sys/chmod.s cc -c /usr/src/libc/sys/chown.s cc -c /usr/src/libc/sys/close.s cc -c /usr/src/libc/sys/creat.s cc -c /usr/src/libc/sys/dup.s cc -c /usr/src/libc/sys/execl.s cc -c /usr/src/libc/sys/execle.s cc -c /usr/src/libc/sys/execv.s cc -c /usr/src/libc/sys/execve.s cc -c /usr/src/libc/sys/exit.s cc -c /usr/src/libc/sys/fork.s cc -c /usr/src/libc/sys/fstat.s cc -c /usr/src/libc/sys/getgid.s cc -c /usr/src/libc/sys/getpid.s cc -c /usr/src/libc/sys/getuid.s cc -c /usr/src/libc/sys/ioctl.s cc -c /usr/src/libc/sys/kill.s cc -c /usr/src/libc/sys/link.s cc -c /usr/src/libc/sys/lock.s cc -c /usr/src/libc/sys/lseek.s cc -c /usr/src/libc/sys/mknod.s cc -c 'usr/src/libc/sys/mount.s cc -c 'usr/src'libc/sys/mpxcall.s cc %c 'usr'src'libc/sys'nice.s cc %c 'usr/src'libc/sys/gpen.s cc %c 'usr'src/libc'sys'pause.s cc %c 'usr'src'libc'sys/phys&s cc %c 'usr'src'libc'sys'pipe&s cc %c 'usr'src'dibc'sys'prgfid.s cc %c 'usr'src'libc'sys'ptrace.s cc %c 'usr/src'libc/sys/read.s cc %c 'usr'src/libc/sys'sbrk.s cc %c 'usr/src/libc/sys/setgid.s cc %c 'usr/src/libc/sys'setuid.s cc -c 'usr/src/libc/sys/signal.s cc -c 'usr/src/libc/sys/stat.s cc -c 'usr/src/libc/sys/stime.s cc -c /usr/src/libc/sys/sync.s cc -c /usr/src/libc/sys/time.s cc -c /usr/src/libc/sys/times.s cc -c /usr/src/libc/sys/umask.s cc -c /usr/src/libc/sys/umount.s cc -c /usr/src/libc/sys/unlink.s cc -c /usr/src/libc/sys/utime.s cc -c /usr/src/libc/sys/wait.s cc -c /usr/src/libc/sys/write.s cc -c /usr/src/libc/crt/aldiv.s cc -c /usr/src/libc/crt/almul.s cc -c /usr/src/libc/crt/alrem.s cc -c /usr/src/libc/crt/cerror.s cc -c /usr/src/libc/crt/ldiv.s cc -c /usr/src/libc/crt/lmul.s cc -c /usr/src/libc/crt/lrem.s cc -c /usr/src/libc/crt/mcount.s cc -c /usr/src/libc/crt/csv.s qf >4N_4/pitt/11stuff/data.c/* * Standard I/O Library structure data for the PDP-11 */ #include struct _file _iofile[_NFILE] = { { 0, 0, 0, NULL, stdin, 0, _IOFUSE+_IOREAD}, { 1, 0, 0, NULL, stdout, 0, _IOFUSE+_IOWRT}, { 2, 0, 0, NULL, stderr, 0, _IOFUSE+_IOWRT}, }; struct _stream _iostrm[_NSTRM] = { { NULL, NULL, NULL, NULL, NULL, &_iofile[0], 0, _IOSUSE}, { NULL, NULL, NULL, NULL, NULL, &_iofile[1], 0, _IOSUSE}, { NULL, NULL, NULL, NULL, NULL, &_iofile[2], 0, _IOSUSE}, }; qe M4MlE4/pitt/11stuff/mklibar rc libc.a \ cuexit.o \ debug.o \ fdup.o \ filbuf.o \ fperror.o \ fputs.o \ freopen.o \ fscratch.o \ ftell.o \ fwipe.o \ gcvt.o \ getchar.o \ getgrgid.o \ getgrnam.o \ getgrent.o \ getpass.o \ fprintf.o \ getpw.o \ getpwnam.o \ getpwuid.o \ getpwent.o \ fgets.o \ fopen.o \ fopensub.o \ gets.o \ getw.o \ makebuf.o \ popen.o \ fdopen.o \ fdopensub.o \ fsalloc.o \ printf.o \ putchar.o \ puts.o \ putw.o \ rdwr.o \ rew.o \ clrerr.o \ fseek.o \ scanf.o \ doscan.o \ fgetc.o \ fget.o \ setbuf.o \ fclose.o \ system.o \ tmpnam.o \ sprintf.o \ fltpr.o \ doprnt.o \ ffltpr.o \ strout.o \ fputc.o \ fput.o \ stdio.o \ ungetc.o \ data.o \ timezone.o \ execvp.o \ getenv.o \ getlogin.o \ perror.o \ sleep.o \ ttyslot.o \ ttyname.o \ abort.o \ abs.o \ atof.o \ atoi.o \ atol.o \ crypt.o \ ctime.o \ calloc.o \ malloc.o \ ecvt.o \ errlst.o \ fakcu.o \ fakfp.o \ frexp11.o \ isatty.o \ l3.o \ ldexp11.o \ ldfps.o \ mktemp.o \ modf11.o \ mon.o \ mpx.o \ nlist.o \ qsort.o \ rand.o \ setjmp.o \ stty.o \ swab.o \ tell.o \ ctype_.o \ index.o \ rindex.o \ strcat.o \ strncat.o \ strcmp.o \ strncmp.o \ strcpy.o \ strncpy.o \ strlen.o \ access.o \ acct.o \ alarm.o \ chdir.o \ chroot.o \ chmod.o \ chown.o \ close.o \ creat.o \ dup.o \ execl.o \ execle.o \ execv.o \ execve.o \ exit.o \ fork.o \ fstat.o \ getgid.o \ getpid.o \ getuid.o \ ioctl.o \ kill.o \ link.o \ lock.o \ lseek.o \ mknod.o \ mount.o \ mpxcall.o \ nice.o \ open.o \ pause.o \ phys.o \ pipe.o \ profil.o \ ptrace.o \ read.o \ sbrk.o \ setgid.o \ setuid.o \ signal.o \ stat.o \ stime.o \ sync.o \ time.o \ times.o \ umask.o \ umount.o \ unlink.o \ utime.o \ wait.o \ write.o \ aldiv.o \ almul.o \ alrem.o \ cerror.o \ ldiv.o \ lmul.o \ lrem.o \ mcount.o \ csv.o cqd G4NT? 4/pitt/11stuff/stdio.h/* * Standard I/O Library definitions for the PDP-11 */ #define BUFSIZ 512 #define _NFILE 20 #define _NSTRM 20 typedef long t_faddr; typedef char t_byte; #define _MAXPNT ((char *) -1) struct _file { char _fildes; /* file descriptor */ char _ferrno; /* error code */ t_faddr _ffaddr; /* file address */ struct _window *_nxwndw; /* to list of windows into this file */ struct _stream *_nxstrm; /* to list of streams using this file */ int _bufsiz; /* window buffer size in bytes */ short _fflags; }; #define _IOREAD 0001 /* reading is permitted */ #define _IOWRT 0002 /* writing is permitted */ #define _IOERR 0004 /* an I/O error has occurred */ #define _IOFBF 0010 /* fancy buffering is performed */ #define _IONBF 0020 /* this file is not buffered */ #define _IOBUF 0040 /* this file is buffered */ #define _IOFUSE 0100 /* this _file structure is in use */ struct _stream { t_byte *_iopos; /* current position in window buffer */ t_byte *_endata; /* to first byte not readable by getc */ t_byte *_endbuf; /* to first byte not writeable by putc */ struct _window *_swndw; /* to currently used window */ struct _stream *_nxstrm; /* to next stream accessing same file */ struct _file *_sfile; /* to file accessed by this stream */ t_faddr _sfaddr; /* stream address if no window */ int _sflags; }; #define _flag _sflags /* because the 11 version of getw() uses this */ #define _IOEOF 001 /* a read was attempted beyond the EOF */ #define _IOFAIL 002 /* an I/O operation has failed */ #define _IOSEEK 004 /* a seek was done past the EOF ???? */ #define _IOSUSE 010 /* this _stream structure is in use */ struct _window { t_byte *_bfbase; /* to first byte in window buffer */ t_byte *_endata; /* to first unfilled byte in buffer */ t_byte *_endbuf; /* to first byte after window buffer */ struct _window *_nxwndw; /* to next window into same file */ struct _stream *_wstrm; /* to stream responsible for window */ struct _file *_wfile; /* to file accessed by this window */ t_faddr _wfaddr; /* file address of this window */ int _wflags; }; #define _IOMOD 01 /* this window has been poked */ struct _file _iofile[_NFILE]; struct _stream _iostrm[_NSTRM]; #define NULL 0 #define FILE struct _stream #define _iobuf _stream /* for compatability */ #define EOF (-1) #define stdin (&_iostrm[0]) #define stdout (&_iostrm[1]) #define stderr (&_iostrm[2]) #define getc(p) ((p)->_iopos >= (p)->_endata ? fgetc(p) \ : *(p)->_iopos++ & 0377) #define putc(x,p) ((p)->_iopos >= (p)->_endbuf ? fputc((unsigned)(x),p) \ : (int) (*(p)->_iopos++ = (unsigned)(x))) #define getwa(p) ((p)->_iopos >= (p)->_endata ? getw(p) \ : *(* (int **) (&(p)->_iopos))++) #define putwa(x,p) ((p)->_iopos >= (p)->_endbuf ? putw(x,p) \ : (*(* (int **) (&(p)->_iopos))++ = x)) #define getchar() getc(stdin) #define putchar(x) putc(x,stdout) #define feof(p) (((p)->_sflags & _IOEOF) != 0) #define ferror(p) (((p)->_sflags & _IOFAIL) != 0) #define fileno(p) ((p)->_sfile->_fildes) FILE *fopen(); FILE *fdopen(); FILE *freopen(); FILE *fdup(); FILE *makebuf(); FILE *fscratch(); long ftell(); char *fgets(); )qc AN4\Λ4/pitt/780stuffqb <4Mby?4/pitt/780stuff/MakefileCFLAGS=-O -I. o=clrerr.o data.o debug.o doprnt.o doscan.o fclose.o \ fdopen.o fdopensub.o fdup.o fget.o fgetc.o fgets.o filbuf.o fopen.o \ fopensub.o fperror.o fprintf.o fput.o fputc.o fputs.o freopen.o \ fsalloc.o fseek.o ftell.o fwipe.o gcvt.o getchar.o getgrent.o getgrgid.o \ getgrnam.o getpass.o getpw.o getpwent.o getpwnam.o getpwuid.o gets.o \ getw.o popen.o printf.o putchar.o puts.o putw.o rdwr.o rew.o \ scanf.o setbuf.o sprintf.o stdio.o strout.o system.o tmpnam.o \ makebuf.o ungetc.o exit.o fscratch.o libS.a : $o ar cr libS.a `lorder $o | tsort` clean : rm -f *.o doprnt.o : cp doprnt.s doprnt.c cc -E doprnt.c | as -o doprnt.o -ld -x -r doprnt.o mv a.out doprnt.o rm doprnt.c exit.o : /usr/src/libc/sys/exit.s as -o exit.o /usr/src/libc/sys/exit.s .c.o : cc $(CFLAGS) -c $*.c .s.o : as -o $*.o $*.s oqa 94N4/pitt/780stuff/data.ce/* * Standard I/O Library structure data for the VAX */ #include struct _file _iofile[_NFILE] = { { 0, 0, _IOFUSE+_IOREAD, 0, 0, NULL, stdin}, { 1, 0, _IOFUSE+_IOWRT, 0, 0, NULL, stdout}, { 2, 0, _IOFUSE+_IOWRT, 0, 0, NULL, stderr}, }; struct _stream _iostrm[_NSTRM] = { { NULL, NULL, NULL, NULL, NULL, &_iofile[0], 0, _IOSUSE}, { NULL, NULL, NULL, NULL, NULL, &_iofile[1], 0, _IOSUSE}, { NULL, NULL, NULL, NULL, NULL, &_iofile[2], 0, _IOSUSE}, }; q` H4NT 4/pitt/780stuff/stdio.h/* * Standard I/O Library definitions for the VAX */ #define BUFSIZ 512 #define _NFILE 20 #define _NSTRM 20 typedef long t_faddr; typedef char t_byte; #define _MAXPNT ((char *) 0x7fffffff) struct _file { char _fildes; /* file descriptor */ char _ferrno; /* error code */ short _fflags; t_faddr _ffaddr; /* file address */ int _bufsiz; /* window buffer size in bytes */ struct _window *_nxwndw; /* to list of windows into this file */ struct _stream *_nxstrm; /* to list of streams using this file */ }; #define _IOREAD 0001 /* reading is permitted */ #define _IOWRT 0002 /* writing is permitted */ #define _IOERR 0004 /* an I/O error has occurred */ #define _IOFBF 0010 /* fancy buffering is performed */ #define _IONBF 0020 /* this file is not buffered */ #define _IOBUF 0040 /* this file is buffered */ #define _IOFUSE 0100 /* this _file structure is in use */ struct _stream { t_byte *_iopos; /* current position in window buffer */ t_byte *_endata; /* to first byte not readable by getc */ t_byte *_endbuf; /* to first byte not writeable by putc */ struct _window *_swndw; /* to currently used window */ struct _stream *_nxstrm; /* to next stream accessing same file */ struct _file *_sfile; /* to file accessed by this stream */ t_faddr _sfaddr; /* stream address if no window */ int _sflags; }; #define _IOEOF 001 /* a read was attempted beyond the EOF */ #define _IOFAIL 002 /* an I/O operation has failed */ #define _IOSEEK 004 /* a seek was done past the EOF ???? */ #define _IOSUSE 010 /* this _stream structure is in use */ struct _window { t_byte *_bfbase; /* to first byte in window buffer */ t_byte *_endata; /* to first unfilled byte in buffer */ t_byte *_endbuf; /* to first byte after window buffer */ struct _window *_nxwndw; /* to next window into same file */ struct _stream *_wstrm; /* to stream responsible for window */ struct _file *_wfile; /* to file accessed by this window */ t_faddr _wfaddr; /* file address of this window */ int _wflags; }; #define _IOMOD 01 /* this window has been poked */ struct _file _iofile[_NFILE]; struct _stream _iostrm[_NSTRM]; #define NULL 0 #define FILE struct _stream #define _iobuf _stream /* for compatability */ #define EOF (-1) #define stdin (&_iostrm[0]) #define stdout (&_iostrm[1]) #define stderr (&_iostrm[2]) #define getc(p) ((p)->_iopos >= (p)->_endata ? fgetc(p) \ : *(p)->_iopos++ & 0377) #define putc(x,p) ((p)->_iopos >= (p)->_endbuf ? fputc((unsigned)(x),p) \ : (int) (*(p)->_iopos++ = (unsigned)(x))) #define getwa(p) ((p)->_iopos >= (p)->_endata ? getw(p) \ : *(* (int **) (&(p)->_iopos))++) #define putwa(x,p) ((p)->_iopos >= (p)->_endbuf ? putw(x,p) \ : (*(* (int **) (&(p)->_iopos))++ = x)) #define getchar() getc(stdin) #define putchar(x) putc(x,stdout) #define feof(p) (((p)->_sflags & _IOEOF) != 0) #define ferror(p) (((p)->_sflags & _IOFAIL) != 0) #define fileno(p) ((p)->_sfile->_fildes) FILE *fopen(); FILE *fdopen(); FILE *freopen(); FILE *fdup(); FILE *makebuf(); FILE *fscratch(); long ftell(); char *fgets(); )q_ ^4QdK4/pitt/README This document describes a buffered I/O package developed from the Standard I/O Library distributed as part of UNIX/32V or UNIX* Version 7. The buffer structure and the routines that manipulate it have been completely redesigned and rewritten but meet the external specifications given in the UNIX PROGRAMMERS MANUAL and should work with all pro- grams that use the standard Standard I/O Library. The difference is the existence of a few new features which are not noticeable unless used. The most important new features are facilities for [1] opening old files for both input and output with the access type string "rw", [2] creating more than one buffer for a single I/O stream, and [3] creating different I/O streams that access the same file and use the same set of buffers but have indepen- dent read/write pointers. _N_E_W _R_O_U_T_I_N_E_S AND _M_A_C_R_O_S FILE *fdup (file) FILE *file; Return a pointer to a new I/O stream that accesses the same file as the argument I/O stream. Return NULL if stream duplication fails. A duplicated I/O stream has an independent read/write pointer. Data written using one I/O stream from a group of duplicated I/O streams is immediately avail- able using any I/O stream from that group even though the new data has not yet been written into the shared file. Duplicated I/O streams have to be closed just like ori- ginal I/O streams. __________________________ *UNIX is a Trademark of Bell Laboratories. April 8, 1980 - 2 - FILE *makebuf (file) FILE *file; Create a new buffer for the file accessed by the argu- ment I/O stream. Return the argument FILE pointer if buffer creation succeeds. Return NULL if buffer crea- tion fails. This routine may be used to cause normally unbuffered I/O streams (like the standard output) to be buffered or to create multiple buffers for a single I/O stream. The effect of multiple buffers is a cache. FILE *setbuff (file, bufp) FILE *file; char *bufp; This routine is like makebuf() except that the address of the new buffer is an argument. If the argument buffer address is NULL, setbuff() will behave exactly like makebuf(). The argument buffer is assumed to be sufficiently large. Use fbufsiz() to find out how big the buffers must be. If aligned transfer macros are used, the buffer should be aligned on a word boundary. Setbuff() is not the same as setbuf(). The setbuf() supplied with the new I/O package is intended to be compatible with the setbuf() in the old I/O package. Setbuf() does not indicate success or failure, gets rid of all previously created buffers for the file accessed by the argument I/O stream, and will turn off buffering if the argument buffer address is NULL. Makebuf() is better than setbuff() and setbuf() because makebuf() does not depend on an unreliable programmer for integrity of it's buffer storage. Use setbuff() instead of makebuf() only when considerable memory can be saved by overlaying buffers with something else. Never look directly into a buffer created with set- buff(). Use setbuf() in new programs only to stop buffering. April 8, 1980 - 3 - int fbufsiz (file) FILE *file; Return the size (in bytes) of the buffers used with the argument I/O stream. If the I/O stream is not buf- fered, return zero. Terminals get a buffer size of 128 bytes and all other devices get a buffer size of BUFSIZ bytes. These numbers are subject to change without notice. int getwa (file) FILE *file; int putwa (n, file) FILE *file; Macros getwa() and putwa() read and write aligned words a tad faster than routines getw() and putw(). The use of aligned transfer macros introduces a  new kind of error that the I/O library routines cannot easily deal with: the misaligned transfer. The possi- bility that an I/O failure might cause a stream to be- come incorrectly aligned must be considered. Program- mers may assume that the aligned transfer macros and attempts to fseek() to aligned addresses will not cause misalignment. fperror (file, str) FILE *file; char *str; When an I/O error is detected on the argument file, the error code is stashed in the buffer structure. Subrou- tine fperror() uses the saved error code and the system subroutine perror() to produce an error message con- taining the argument character string. char *sprntfn (str, strend, format, par1, ...) char *str, *strend, *format; Routine sprntfn() is similar to routine sprintf(). Ar- gument "strend" points to the first character following the character array "str". If the character string produced by sprntfn() is too large to fit in "str", it is truncated. A trailing '\0' is guaranteed if str < strend. The value of this function is a pointer to the '\0'. April 8, 1980 - 4 - FILE *fscratch (name, visible) char *name; Replace the argument file name with the name of a nonexistant file using the system routine mktemp(). Create this file, close it, and reopen it for both read and write access. If the argument visibility flag is zero, unlink the file immediately. Return the I/O stream with read/write access. Return NULL if scratch file creation fails. fwipe (file) FILE *file; Clear all buffers for the file accessed by the argument I/O stream. If the I/O stream is currently connected to a buffer, reposition the read/write pointer to the beginning of the buffer. This routine was developed to be used for cancelling buffered terminal output after catching an interrupt signal. Possible interactions with other I/O routines in complicated situations (e.g. when multiple streams and buffers are connected to the same file) have not been considered. _P_I_T_F_A_L_L_S AND _U_S_E_F_U_L _T_R_I_V_I_A The buffer management routines keep track of consider- able detail so that programmers do not have to. These rou- tines can be used without familiarity with their internal workings. Nevertheless some knowledge of their behavior may be useful. A buffering scheme appropriate for regular disk files carefully aligns buffers on block boundaries, attempts to output only full buffers, and remembers the contents of old buffers. A buffering scheme appropriate for terminals does not bother aligning buffers, does not output data that has already been flushed, and ignores the contents of old buffers. Therefore the buffer management routines use two different algorithms. The default is appropriate for termi- nals and for sequential access to disk files. Duplicating an I/O stream with fdup(), creating multiple buffers with makebuf(), and fseek()ing to any part of a file other than the beginning cause buffers to be carefully aligned on block boundaries. This may cause strange behavior with write only files and sequential devices like terminals. After an I/O routine (e.g. getc()) is invoked, the April 8, 1980 - 5 - argument I/O stream is associated with the buffer that con- tains the byte of the file that was read or written. This buffer is considered to be 'used' by the I/O stream and will not be reused by another I/O stream to access a different part of the file as long as the first (or any other) I/O stream remains connected to it. A buffer is automatically created when an I/O routine is invoked and all existing buffers are in use. A buffer 'belongs' to the I/O stream for which it was created and goes away when that I/O stream is closed. If an I/O stream is connected to a buffer when that buffer goes away, the stream is forcibly disconnected from that buffer and will be allocated a new buffer when (if) another access is made to the same piece of the file. All of this finaglement is invisible outside of the buffer manipulation routines but does have a few side effects. If an I/O stream is to be periodically duplicated, it is more efficient to create multiple buffers for the ori- ginal stream than to permit buffers to be dynamically created and destroyed as the temporary streams are dupli- cated and closed. Not only does this save an unknown but probably trivial amount of cpu time in the dynamic storage allocation routines, but this also saves the buffer contents which the program very likely has no further interest in. Still, it might. _E_F_F_I_C_I_E_N_C_Y The buffer manipulation routines (found mainly in stdio.c) are a bit involved because they have to support multiple buffering of files shared by several I/O streams. Complication is always expensive. This Standard I/O Library requires about 4K byte[1]. The standard Standard I/O Library requires about 3K byte (try "ld -u _fopen -u _getw -u _fclose -lc"). Changing buffers (something one does every 512 getc's) burns up about 300 us in the buffer manipulation routines. Since reading a block requires 2 or 3 ms of system time (is this excessive?) the buffer manipulation time is not too painful. The old getc() macro requires about 4.5 us[2]. The new getc() macro requires about 4.9 us. The difference is less than 10% or about 200 us per 512 byte disk block. __________________________ [1] All program sizes and speeds were measured on the VAX-11/780 running UNIX/32V. [2] You may be able to trim about 0.5 us off this by reversing the order of the alternatives in the macro definition. 250 us per block may not seem like much, but it is very easy to get. April 8, 1980 - 6 - This new buffered I/O package is a bit slower and larger than the old one, but does provide a few new features that are occasionally useful (see below for guidance on 'occasionally'[3]). Very few real programs (I don't offhand know of any) spend such a large amount of their time in the Standard I/O Library that the increase would be measurable. On the other hand, this new I/O package does do some things more quickly. The getwa() macro uses about 5 us while the getw() routine uses about 70 us. The new ftell() routine figures out the current file address by examining the contents of the buffer structures. The old ftell() rou- tine probably runs a hundred times slower because it uses a system call to get the current buffer address, but most pro- grams seldom call ftell(). The new I/O package aligns buffers on block boundaries after fseek()s. The old I/O package does not; this could double the number of disk accesses required (but is usually saved by the system buffer pool?). _I_N_S_T_A_L_L_A_T_I_O_N The directory in which you found the file you are read- ing contains the new buffered I/O routines packaged together with the Standard I/O Library routines that were not rewrit- ten. The new buffered I/O routines could conceivably have been extracted as an I/O package not covered by the non- disclosure agreement, but this would make installation more difficult. In any case, why should I stick my neck out? These routines are to be distributed only to institutions that have a source license for UNIX/32V or Version 7. If your institution doesn't have such a license, close your eyes before reading further. Contrary to popular DEC mythology, a VAX 11/780 is not just like a PDP 11 (only better). Therefore you will find a pair of subdirectories, that contain the differences between the VAX 11/780 and the PDP 11 versions of the library: "11stuff" and "780stuff". Copy the contents of the appropriate subdirectory into the top level directory. A few of the differences may be covered by the non-disclosure agreement. You will have to retrieve them from the Standard I/O Library source distributed with UNIX32/V or Version 7 (directory /usr/src/libc/stdio). These files are named "doprnt.s", "getw.c", "putw.c", and "strout.c". PDP 11's also need "fltpr.s" and "ffltpr.s". One of the files in the top level directory is called __________________________ [3] An efficient programmer uses code written by oth- ers. April 8, 1980 - 7 - Makefile. It is used with the make program to build "libS.a". Makefile has a reference to the file /usr/src/libc/sys/exit.s (cuexit.s in Version 7). This is because the exit() routine in "libc.a" invokes _cleanup() in fclose.c and must therefore appear in an object library before fclose.o. If you are not using a "vanilla" UNIX/32V or Version 7, you may have to change this. To use this Standard I/O Library, compile all routines that use it with the include file "stdio.h" found in this directory and load them with the "libS.a" created by the Makefile. The new Standard I/O Library routines and header file are not compatible with the old. Mixing the two causes mysterious core dumps and severe indigestion. Fortunately most of the references to the Standard I/O Library primi- tives are found in the standard I/O library. In UNIX Ver- sion 7, "libc.a" is clean. In UNIX/32V, "libc.a" contains references to the Standard I/O Library in "rin.c" (which does what?) and "ttytest.c" (which does nothing useful). Unfortunately the FORTRAN library is dirty. The incompati- bility will probably not be a real problem if you are care- ful. I have never tried to replace the Standard I/O Library in the system libraries with this version because it is easy enough to use from a private library, but if you are brave enough to give it a shot, I will gladly suggest an approach. 1. Replace the contents of /usr/src/libc/stdio with the contents of this directory. Copy the new stdio.h into /usr/include. 2. Invoke the Makefiles in /usr/src/libc, /usr/src/libF77, and /usr/src/libI77. Search the other libraries for references to stdio.h and remake everything that you find. If you have a PDP 11, the files compall and mklib are used to remake things. An untested pair for libc.a may be found in subdirectory 11stuff. 3. You might as well find out now what won't work with the new I/O package. Remake everything. I don't really know how to do this. I suggest you make very sure the new C-compiler works. 4. If you don't like the results, restore the entire sys- tem from the dump tapes you made even though I didn't suggest it. 5. If you do like the results, tell all of your users that they had better recompile all of their programs "just in case". April 8, 1980 - 8 - _U_T_I_L_I_T_Y Why should you consider using this I/O package rather than the standard one? This I/O package supports read/write files (update mode). Processes that need to read and write random bytes in a file are not uncommon. Consider the fol- lowing example. Suppose we want a program to store lists of integers in a scratch file. Suppose a list may contain as few as one integer or as many as 20,000 integers. Suppose we want the program to be able to form a new list in the scratch file by merging two previously created lists that are also in that file (or possibly in a different file). One obvious implementation would involve a routine that accepted three I/O streams as arguments. The subroutine would assume that the I/O streams were completely indepen- dent and had been positioned to the locations of the input integer lists and the desired location of the output integer list. This could be arranged using the old I/O library by opening the scratch file three times (expensive). An integer list has to be readable by an input stream as soon as it is finished. Therefore the output stream must be flushed at the end of each list (expensive for short lists), causing the next I/O buffer to be incorrectly aligned (expensive). Alternatively, each output integer list may be padded to exactly fill the last output buffer used (expen- sive for short lists), but this is painful because the pro- gram must concern itself with grubby details like block sizes and block alignment. If you do like to deal with issues like these, IBM makes some very nice operating sys- tems. If the new I/O library is used, the scratch file can be opened once for both input and output with fscratch(). Three buffers for the file may be created with makebuf(). When the lists of integers are to be merged, independent file pointers for reading the existing lists may be obtained by duplicating the original I/O stream (which will be used for output). When the new integer list is finished, the duplicated I/O streams may be disposed of with fclose(). The new integer list does not have to be padded and the out- put I/O stream does not have to be flushed. If any of the three lists occupy common blocks, the buffer manipulation routines will arrange that the corresponding I/O streams access the same buffers. The program (programmer) does not have to worry about any of the messy details as the I/O library makes efficient use of the buffered file data. If the aligned word transfer macros are used, the merging pro- cess could run twice as quickly. Even if you don't have applications like this in mind, you might want to update a file sometimes. Or perhaps you might want to write some temporary data into a scratch file, April 8, 1980 - 9 - rewind it, and read it. The use of this library might increase the portability of programs that update files. If this library is installed in the system as the Standard I/O Library, it becomes easier to use in those occasional cir- cumstances when something more versatile than the old I/O library is needed. I have been using this I/O library since July 1979 and it seems to be very reliable, but if anyone should happen to discover a bug, I would be very pleased to hear about it. Daniel R. Strick Office of Communications Programs 808 LIS Building University of Pittsburgh Pittsburgh, PA. 15260 April 8, 1980 eq^ 4Qzc D4/pitt/README.nrf....nroff this with the -ms macro package .LP This document describes a buffered I/O package developed from the Standard I/O Library distributed as part of UNIX/32V or .UX Version 7. The buffer structure and the routines that manipulate it have been completely redesigned and rewritten but meet the external specifications given in the UNIX PROGRAMMERS MANUAL and should work with all programs that use the standard Standard I/O Library. The difference is the existence of a few new features which are not noticeable unless used. .LP The most important new features are facilities for .IP [1] opening old files for both input and output with the access type string "rw", .IP [2] creating more than one buffer for a single I/O stream, and .IP [3] creating different I/O streams that access the same file and use the same set of buffers but have independent read/write pointers. .sp 2 .LP .UL NEW .UL ROUTINES AND .UL MACROS .sp .KS .LP FILE *fdup (file) .br FILE *file; .RS .LP Return a pointer to a new I/O stream that accesses the same file as the argument I/O stream. Return NULL if stream duplication fails. .LP A duplicated I/O stream has an independent read/write pointer. Data written using one I/O stream from a group of duplicated I/O streams is immediately available using any I/O stream from that group even though the new data has not yet been written into the shared file. .LP Duplicated I/O streams have to be closed just like original I/O streams. .RE .KE .sp .KS .LP FILE *makebuf (file) .br FILE *file; .RS .LP Create a new buffer for the file accessed by the argument I/O stream. Return the argument FILE pointer if buffer creation succeeds. Return NULL if buffer creation fails. .LP This routine may be used to cause normally unbuffered I/O streams (like the standard output) to be buffered or to create multiple buffers for a single I/O stream. The effect of multiple buffers is a cache. .RE .KE .sp .KS .LP FILE *setbuff (file, bufp) .br FILE *file; .br char *bufp; .RS .LP This routine is like makebuf() except that the address of the new buffer is an argument. If the argument buffer address is NULL, setbuff() will behave exactly like makebuf(). .LP The argument buffer is assumed to be sufficiently large. Use fbufsiz() to find out hgw big the buffers must be. If aligned transfer macros are used, the buffer should be aligned on a word boundary. .LP Setbuff() is not the same as setbuf(). The setbuf() supplied with the new I/O package is intended to be compatible with the setbuf() in the old I/O package. Setbuf() does not indicate success or failure, gets rid of all previously created buffers for the file accessed by the argument I/O stream, and will turn off buffering if the argument buffer address is NULL. .LP Makebuf() is better than setbuff() and setbuf() because makebuf() does not depend on an unreliable programmer for integrity of it's buffer storage. Use setbuff() instead of makebuf() only when considerable memory can be saved by overlaying buffers with something else. Never look directly into a buffer created with setbuff(). Use setbuf() in new programs only to stop buffering. .RE .KE .sp .KS .LP int fbufsiz (file) .br FILE *file; .RS .LP Return the size (in bytes) of the buffers used with the argument I/O stream. If the I/O stream is not buffered, return zero. .LP Terminals get a buffer size of 128 bytes and all other devices get a buffer size of BUFSIZ bytes. These numbers are subject to change without notice. .RE .KE .sp .KS .LP int getwa (file) .br FILE *file; .sp int putwa (n, file) .br FILE *file; .RS .LP Macros getwa() and putwa() read and write aligned words a tad faster than routines getw() and putw(). .LP The use of aligned transfer macros introduces a new kind of error that the I/O library routines cannot easily deal with: the misaligned transfer. The possibility that an I/O failure might cause a stream to become incorrectly aligned must be considered. Programmers may assume that the aligned transfer macros and attempts to fseek() to aligned addresses will not cause misalignment. .RE .KE .sp .KS .LP fperror (file, str) .br FILE *file; .br char *str; .RS .LP When an I/O error is detected on the argument file, the error code is stashed in the buffer structure. Subroutine fperror() uses the saved error code and the system subroutine perror() to produce an error message containing the argument character string. .RE .KE .sp .KS .LP char *sprntfn (str, strend, format, par1, ...) .br char *str, *strend, *format; .RS .LP Routine sprntfn() is similar to routine sprintf(). Argument "strend" points to the first character following the character array "str". If the character string produced by sprntfn() is too large to fit in "str", it is truncated. A trailing '\\\\0' is guaranteed if str < strend. The value of this function is a pointer to the '\\\\0'. .RE .KE .sp .KS .LP FILE *fscratch (name, visible) .br char *name; .RS .LP Replace the argument file name with the name of a nonexistant file using the system routine mktemp(). Create this file, close it, and reopen it for both read and write access. If the argument visibility flag is zero, unlink the file immediately. Return the I/O stream with read/write access. Return NULL if scratch file creation fails. .RE .KE .sp .KS .LP fwipe (file) .br FILE *file; .RS .LP Clear all buffers for the file accessed by the argument I/O stream. If the I/O stream is currently connected to a buffer, reposition the read/write pointer to the beginning of the buffer. .LP This routine was developed to be used for cancelling buffered terminal output after catching an interrupt signal. Possible interactions with other I/O routines in complicated situations (e.g. when multiple streams and buffers are connected to the same file) have not been considered. .RE .KE .sp2 .LP .UL PITFALLS AND .UL USEFUL .UL TRIVIA .PP The buffer management routines keep track of considerable detail so that programmers do not have to. These routines can be used without familiarity with their internal workings. Nevertheless some knowledge of their behavior may be useful. .PP A buffering scheme appropriate for regular disk files carefully aligns buffers on block boundaries, attempts to output only full buffers, and remembers the contents of old buffers. A buffering scheme appropriate for terminals does not bother aligning buffers, does not output data that has already been flushed, and ignores the contents of old buffers. Therefore the buffer management routines use two different algorithms. The default is appropriate for terminals and for sequential access to disk files. Duplicating an I/O stream with fdup(), creating multiple buffers with makebuf(), and fseek()ing to any part of a file other than the beginning cause buffers to be carefully aligned on block boundaries. This may cause strange behavior with write only files and sequential devices like terminals. .PP After an I/O routine (e.g. getc()) is invoked, the argument I/O stream is associated with the buffer that contains the byte of the file that was read or written. This buffer is considered to be 'used' by the I/O stream and will not be reused by another I/O stream to access a different part of the file as long as the first (or any other) I/O stream remains connected to it. A buffer is automatically created when an I/O routine is invoked and all existing buffers are in use. A buffer 'belongs' to the I/O stream for which it was created and goes away when that I/O stream is closed. If an I/O stream is connected to a buffer when that buffer goes away, the stream is forcibly disconnected from that buffer and will be allocated a new buffer when (if) another access is made to the same piece of the file. .PP All of this finaglement is invisible outside of the buffer manipulation routines but does have a few side effects. If an I/O stream is to be periodically duplicated, it is more efficient to create multiple buffers for the original stream than to permit buffers to be dynamically created and destroyed as the temporary streams are duplicated and closed. Not only does this save an unknown but probably trivial amount of cpu time in the dynamic storage allocation routines, but this also saves the buffer contents which the program very likely has no further interest in. Still, it might. .sp 2 .LP .UL EFFICIENCY .PP The buffer manipulation routines (found mainly in stdio.c) are a bit involved because they have to support multiple buffering of files shared by several I/O streams. Complication is always expensive. This Standard I/O Library requires about 4K byte[1]. .FS [1] All program sizes and speeds were measured on the VAX-11/780 running UNIX/32V. .FE The standard Standard I/O Library requires about 3K byte (try "ld -u _fopen -u _getw -u _fclose -lc"). .PP Changing buffers (something one does every 512 getc's) burns up about 300 us in the buffer manipulation routines. Since reading a block requires 2 or 3 ms of system time (is this excessive?) the buffer manipulation time is not too painful. The old getc() macro requires about 4.5 us[2]. .FS [2] You may be able to trim about 0.5 us off this by reversing the order of the alternatives in the macro definition. 250 us per block may not seem like much, but it is very easy to get. .FE The new getc() macro requires about 4.9 us. The difference is less than 10% or about 200 us per 512 byte disk block. .PP This new buffered I/O package is a bit slower and larger than the old one, but does provide a few new features that are occasionally useful (see below for guidance on 'occasionally'[3]). .FS [3] An efficient programmer uses code written by others. .FE Very few real programs (I don't offhand know of any) spend such a large amount of their time in the Standard I/O Library that the increase would be measurable. .PP On the other hand, this new I/O package does do some things more quickly. The getwa() macro uses about 5 us while the getw() routine uses about 70 us. The new ftell() routine figures out the current file address by examining the contents of the buffer structures. The old ftell() routine probably runs a hundred times slower because it uses a system call to get the current buffer address, but most programs seldom call ftell(). The new I/O package aligns buffers on block boundaries after fseek()s. The old I/O package does not; this could double the number of disk accesses required (but is usually saved by the system buffer pool?). .sp 2 .LP .UL INSTALLATION .PP The directory in which you found the file you are reading contains the new buffered I/O routines packaged together with the Standard I/O Library routines that were not rewritten. The new buffered I/O routines could conceivably have been extracted as an I/O package not covered by the non-disclosure agreement, but this would make installation more difficult. In any case, why should I stick my neck out? These routines are to be distributed only to institutions that have a source license for UNIX/32V or Version 7. If your institution doesn't have such a license, close your eyes before reading further. .PP Contrary to popular DEC mythology, a VAX 11/780 is not just like a PDP 11 (only better). Therefore you will find a pair of subdirectories, that contain the differences between the VAX 11/780 and the PDP 11 versions of the library: "11stuff" and "780stuff". Copy the contents of the appropriate subdirectory into the top level directory. A few of the differences may be covered by the non-disclosure agreement. You will have to retrieve them from the Standard I/O Library source distributed with UNIX32/V or Version 7 (directory /usr/src/libc/stdio). These files are named "doprnt.s", "getw.c", "putw.c", and "strout.c". PDP 11's also need "fltpr.s" and "ffltpr.s". .PP One of the files in the top level directory is called Makefile. It is used with the make program to build "libS.a". Makefile has a reference to the file /usr/src/libc/sys/exit.s (cuexit.s in Version 7). This is because the exit() routine in "libc.a" invokes _cleanup() in fclose.c and must therefore appear in an object library before fclose.o. If you are not using a "vanilla" UNIX/32V or Version 7, you may have to change this. .PP To use this Standard I/O Library, compile all routines that use it with the include file "stdio.h" found in this directory and load them with the "libS.a" created by the Makefile. The new Standard I/O Library routines and header file are not compatible with the old. Mixing the two causes mysterious core dumps and severe indigestion. Fortunately most of the references to the Standard I/O Library primitives are found in the standard I/O library. In UNIX Version 7, "libc.a" is clean. In UNIX/32V, "libc.a" contains references to the Standard I/O Library in "rin.c" (which does what?) and "ttytest.c" (which does nothing useful). Unfortunately the FORTRAN library is dirty. The incompatibility will probably not be a real problem if you are careful. .PP I have never tried to replace the Standard I/O Library in the system libraries with this version because it is easy enough to use from a private library, but if you are brave enough to give it a shot, I will gladly suggest an approach. .IP 1. Replace the contents of /usr/src/libc/stdio with the contents of this directory. Copy the new stdio.h into /usr/include. .IP 2. Invoke the Makefiles in /usr/src/libc, /usr/src/libF77, and /usr/src/libI77. Search the other libraries for references to stdio.h and remake everything that you find. If you have a PDP 11, the files compall and mklib are used to remake things. An untested pair for libc.a may be found in subdirectory 11stuff. .IP 3. You might as well find out now what won't work with the new I/O package. Remake everything. I don't really know how to do this. I suggest you make very sure the new C-compiler works. .IP 4. If you don't like the results, restore the entire system from the dump tapes you made even though I didn't suggest it. .IP 5. If you do like the results, tell all of your users that they had better recompile all of their programs "just in case". .sp 2 .LP .UL UTILITY .PP Why should you consider using this I/O package rather than the standard one? This I/O package supports read/write files (update mode). Processes that need to read and write random bytes in a file are not uncommon. Consider the following example. Suppose we want a program to store lists of integers in a scratch file. Suppose a list may contain as few as one integer or as many as 20,000 integers. Suppose we want the program to be able to form a new list in the scratch file by merging two previously created lists that are also in that file (or possibly in a different file). One obvious implementation would involve a routine that accepted three I/O streams as arguments. The subroutine would assume that the I/O streams were completely independent and had been positioned to the locations of the input integer lists and the desired location of the output integer list. .PP This could be arranged using the old I/O library by opening the scratch file three times (expensive). An integer list has to be readable by an input stream as soon as it is finished. Therefore the output stream must be flushed at the end of each list (expensive for short lists), causing the next I/O buffer to be incorrectly aligned (expensive). Alternatively, each output integer list may be padded to exactly fill the last output buffer used (expensive for short lists), but this is painful because the program must concern itself with grubby details like block sizes and block alignment. If you do like to deal with issues like these, IBM makes some very nice operating systems. .PP If the new I/O library is used, the scratch file can be opened once for both input and output with fscratch(). Three buffers for the file may be created with makebuf(). When the lists of integers are to be merged, independent file pointers for reading the existing lists may be obtained by duplicating the original I/O stream (which will be used for output). When the new integer list is finished, the duplicated I/O streams may be disposed of with fclose(). The new integer list does not have to be padded and the output I/O stream does not have to be flushed. If any of the three lists occupy common blocks, the buffer manipulation routines will arrange that the corresponding I/O streams access the same buffers. The program (programmer) does not have to worry about any of the messy details as the I/O library makes efficient use of the buffered file data. If the aligned word transfer macros are used, the merging process could run twice as quickly. .PP Even if you don't have applications like this in mind, you might want to update a file sometimes. Or perhaps you might want to write some temporary data into a scratch file, rewind it, and read it. The use of this library might increase the portability of programs that update files. If this library is installed in the system as the Standard I/O Library, it becomes easier to use in those occasional circumstances when something more versatile than the old I/O library is needed. .PP I have been using this I/O library since July 1979 and it seems to be very reliable, but if anyone should happen to discover a bug, I would be very pleased to hear about it. .RS .RS .RS .sp .LP Daniel R. Strick .br Office of Communications Programs .br 808 LIS Building .br University of Pittsburgh .br Pittsburgh, PA. 15260 .RE .RE .RE dq] 4J|4/pitt/clrerr.c#include clearerr(sp) register struct _stream *sp; { sp->_sflags &= ~(_IOEOF|_IOFAIL); sp->_sfile->_fflags &= ~_IOERR; } q\ 4P! 4/pitt/debug.c/* * Substitute printf() for when the * I/O library really doesn't work * * Daniel R. Strick * * 4/6/80 -- written * 4/7/80 -- tested */ #include _putchr (c) { write (1, &c, 1); } _putlng (ln, base) long ln; { register long n; register int r; n = ln; if (n < 0) { /* a temporary fudge */ _putchr ('-'); n = -n; } r = n % base; n = n / base; if (n != 0) _putlng (n, base); if (r < 10) _putchr ('0' + r); else _putchr ('A' + r - 10); } _putint (n, base) unsigned int n; { _putlng ((long) n, base); } _printf (format, params) char *format; int params; { register int *pp; register char *cp; pp = ¶ms; for (cp = format; *cp != '\0'; ) { if (*cp++ != '%') { _putchr (cp[-1]); continue; } switch (*cp++) { case 'c': _putchr (*pp++); break; case 's': { register char *q; for (q = (char *) *pp++; *q != '\0'; ) _putchr (*q++); break; } case 'd': if (*pp < 0) { _putchr ('-'); _putint (-*pp++, 10); } else _putint ( *pp++, 10); break; case 'u': _putint (*pp++, 10); break; case 'o': _putint (*pp++, 8); break; case 'x': _putint (*pp++, 16); break; case 'D': if (*(long*)pp < 0) { _putchr ('-'); _putlng (-*(long*)pp, 10); } else _putlng ( *(long*)pp, 10); pp = (int*) (((long*) pp) + 1); break; case 'U': _putlng (*(long*)pp, 10); pp = (int*) (((long*) pp) + 1); break; case 'O': _putlng (*(long*)pp, 8); pp = (int*) (((long*) pp) + 1); break; case 'X': _putlng (*(long*)pp, 16); pp = (int*) (((long*) pp) + 1); break; default: _putchr ('%'); case '%': _putchr (cp[-1]); } } } /* * List the contents of the stdio.h data structures for * the argument I/O stream, the file it is connected to, * and the window it is connected to. * * Daniel R. Strick * * 2/24/80 -- written * 2/24/80 -- tested * 4/6/80 -- modified to use _printf() instead of printf() * 4/7/80 -- modified to use a long format for printing file addresses */ _prtstr (sp) register struct _stream *sp; { register struct _file *fp; register struct _window *wp; if (sp == NULL) { _printf ("NULL stream!\n"); return; } _printf ("strm:%x iopos:%x endata:%x endbuf:%x faddr:%O flags:%o\n", sp, sp->_iopos, sp->_endata, sp->_endbuf, sp->_sfaddr, sp->_sflags); fp = sp->_sfile; if (fp == NULL) { _printf("NULL file!\n"); return; } _printf ("file:%x faddr:%O bufsiz:%d errno:%d flags:%o\n", fp, fp->_ffaddr, fp->_bufsiz, fp->_ferrno, fp->_fflags); wp = sp->_swndw; if (wp == NULL) { _printf ("NULL window!\n"); return; } _printf ("wndw:%x base:%x endata:%x endbuf:%x faddr:%O flags:%o\n", wp, wp->_bfbase, wp->_endata, wp->_endbuf, wp->_wfaddr, wp->_wflags); } sq[ 44/pitt/doscan.c#include #include #define SPC 01 #define STP 02 #define SHORT 0 #define REGULAR 1 #define LONG 2 #define INT 0 #define FLOAT 1 char *_getccl(); char _sctab[128] = { 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, }; _doscan(iop, fmt, argp) FILE *iop; register char *fmt; register int **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; ptr = 0; if (ch != '*') ptr = argp++; else ch = *fmt++; 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); } } } _innum(ptr, type, len, size, iop, eofptr) int **ptr, *eofptr; struct _iobuf *iop; { extern double atof(); register char *np; char numbuf[64]; register c, base; int expseen, scale, negflg, c1, ndigit; long lcval; if (type=='c' || type=='s' || type=='[') return(_instr(ptr? *(char **)ptr: (char *)NULL, 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) return(0); *np++ = 0; switch((scale<<4) | size) { case (FLOAT<<4) | SHORT: case (FLOAT<<4) | REGULAR: **(float **)ptr = atof(numbuf); break; case (FLOAT<<4) | LONG: **(double **)ptr = atof(numbuf); break; 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); } _instr(ptr, type, len, iop, eofptr) register char *ptr; register struct _iobuf *iop; int *eofptr; { register 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 (_sctab[ch = getc(iop)] & ignstp) if (ch==EOF) break; 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); } char * _getccl(s) register char *s; { register c, t; t = 0; if (*s == '^') { t++; s++; } for (c = 0; c < 128; c++) if (t) _sctab[c] &= ~STP; else _sctab[c] |= STP; while (((c = *s++)&0177) != ']') { if (t) _sctab[c++] |= STP; else _sctab[c++] &= ~STP; if (c==0) return(--s); } return(s); } }qZ 43k.) 4/pitt/fclose.c#include /* * Flush all windows into the file * accessed by the argument I/O stream. * The value of this function is EOF if * it fails and 0 if it succeeds. * * Daniel R. Strick * * 7/5/79 -- written * ?????? -- tested */ fflush(sp) struct _stream *sp; { register struct _window *wp; struct _window *_wflush(); for (wp = sp->_sfile->_nxwndw; wp != NULL; wp = wp->_nxwndw) if (_wflush(wp) == NULL) return(EOF); return(0); } /* * The NEXT window in the argument window list is flushed * and removed from the list. * All streams that are connected to it are disconnected. * The window's storage is freed with free(). * The argument window list is returned (unless something * goes wrong in which case NULL is returned). * * Daniel R. Strick * * 7/9/79 -- written * ?????? -- tested * 3/17/80 -- fixed bugs: (1) the check for streams connected * to the window being deleted was insane and (2) * the possibility that detach() might move the * window being deleted to the end of the list * was ignored (this is also insane) */ struct _window * _nwfree(wl) register struct _window *wl; { register struct _window *wp; register struct _stream *sp; struct _window *_wflush(); wp = wl->_nxwndw; if (wp == NULL) return(NULL); if (_wflush(wp) == NULL) return(NULL); for (sp = wp->_wfile->_nxstrm; sp != NULL; sp = sp->_nxstrm) if (sp->_swndw == wp) _detach(sp); while (wl != NULL && wl->_nxwndw != wp) wl = wl->_nxwndw; if (wl != NULL) wl->_nxwndw = wp->_nxwndw; free(wp); return(wl); } /* * Close the argument I/O stream. * The stream is flushed, all windows created for * the stream are freed, and the stream structure * is freed. If this stream was the only stream * that accessed accessed its file, the file * descriptor is closed and the file structure * is freed. * The value of this function is EOF if it fails * and 0 if it succeeds. * * Daniel R. Strick * * 7/5/79 -- written * ?????? -- tested * 7/9/79 -- modified to use _nwfree() to free windows. * 1/21/80 -- fixed bug: incorrect check for window ownership */ fclose(sp) register struct _stream *sp; { register struct _window *wp, *dwp; if (fflush(sp) != 0) return(EOF); for (wp = (struct _window *) sp->_sfile; (dwp = wp->_nxwndw) != NULL; ) { if (dwp->_wstrm != sp) wp = dwp; else if (_nwfree(wp) == NULL) return(EOF); } _detach(sp); { register struct _stream *sp2; sp2 = (struct _stream *) sp->_sfile; while (sp2 != NULL) { if (sp2->_nxstrm == sp) sp2->_nxstrm = sp->_nxstrm; sp2 = sp2->_nxstrm; } } sp->_sflags = 0; { register struct _file *fp; fp = sp->_sfile; sp->_sfile = NULL; /* because of stdXXX */ if (fp->_nxstrm == NULL) { fp->_fflags = 0; if (close(fp->_fildes) < 0) return(EOF); } } return(0); } /* * Close all streams. * This routine is supposedly invoked by the standard * exit routine before executing the exit system call. * This ensures that all buffered output is flushed. * Letting the system flush output here is a bit * sloppy since no indication is given if something * goes wrong. * * Daniel R. Strick * * 7/5/79 -- written * ?????? -- tested */ _cleanup() { register struct _stream *sp; for (sp = &_iostrm[0]; sp < &_iostrm[_NSTRM]; ++sp) if (sp->_sflags & _IOSUSE) fclose(sp); } lqY 4z4/pitt/fdopen.c#include FILE * fdopen(fd, mode) char *mode; { FILE *_fdopen(); return(_fdopen(fd, mode, (FILE *) NULL)); } qX 4;Y4/pitt/fdopensub.ci#include #define EOS '\0' #define pair(a,b) (a + (b << 8)) /* * Set up a file structure and a stream structure to access * the file that has already been opened on the the argument * file descriptor. This file descriptor is assumed to * provide the access specified in the argument mode. * If the argument stream pointer is not NULL, this * stream will be used; this gimmick is included for * the benefit of freopen() which ought not to be * necessary anyway. * A pointer to the created stream structure is returned. * If an error is detected, the argument file descriptor * is closed and NULL is returned. * * Daniel R. Strick * * 7/5/79 -- written * ?????? -- tested * 7/9/79 -- modified to allocate streams with _fsalloc() * 3/21/80 -- removed file size initialization * 3/23/80 -- modified to initialize the buffer size to zero */ FILE * _fdopen(fd, mode, stream) register char *mode; struct _stream *stream; { register struct _stream *sp; register struct _file *fp; struct _stream *_fsalloc(); long lseek(); sp = stream; if (sp == NULL) { sp = _fsalloc(); if (sp == NULL) goto error; } for (fp = &_iofile[0]; ; ++fp) { if (fp >= &_iofile[_NFILE]) goto error; if ((fp->_fflags & _IOFUSE) == 0) break; } if (mode[1] != EOS && mode[2] != EOS) goto error; switch (pair(mode[0], mode[1])) { case pair('r', EOS): fp->_fflags = _IOFUSE + _IOREAD; break; case pair('w', EOS): case pair('a', EOS): fp->_fflags = _IOFUSE + _IOWRT; break; case pair('r', 'w'): fp->_fflags = _IOFUSE + _IOREAD + _IOWRT; break; default: goto error; } fp->_ffaddr = lseek(fd, 0L, 1); fp->_bufsiz = 0; fp->_nxwndw = NULL; fp->_nxstrm = sp; fp->_fildes = fd; fp->_ferrno = 0; sp->_sfile = fp; sp->_sfaddr = fp->_ffaddr; sp->_sflags = _IOSUSE; return(sp); error: close(fd); return(NULL); } qW 44/pitt/fdup.c#include /* * Return a pointer to a new I/O stream that is * identical to the argument stream. * Return NULL if the new stream cannot be created. * Duplicating a stream may change its behavior * because this sets the fancy buffering flag. * * Daniel R. Strick * * 7/9/79 -- written * 7/12/79 -- tested */ struct _stream * fdup(osp) register struct _stream *osp; { register struct _stream *sp; register struct _file *fp; struct _stream *_fsalloc(); if ((fp = osp->_sfile) == NULL) return(NULL); if ((sp = _fsalloc()) == NULL) return(NULL); *sp = *osp; osp->_nxstrm = sp; fp->_fflags |= _IOFBF; return(sp); } qV 4;'4/pitt/fget.c#include /* * This kludgy little routine is a collection of all those * things that the fgetx() routines would have in common. * It is called when the fgetx() routine discovers that * there is not enough stuff in the buffer described by * the _stream structure to satisfy its caller. This routine * will then do the "appropriate thing" and return: * -1 -- if something went wrong and the caller should return EOF, * 0 -- if the stream turned out not to be buffered and the * desired data was stashed in the argument buffer, or * 1 -- if the the stream was buffered, the stream was * reconnected to the correct window, and that window * contained (or was made to contain) enough data. * * The "appropriate thing" is to make sure that the stream * is associated with a file that has read access, to decide * if the stream is buffered, and either connect the stream * to a sufficiently filled window or read the data directly * into the argument buffer. * * Daniel R. Strick * * 7/11/79 -- written * 7/12/79 -- tested * 3/21/80 -- modified to attempt to fill insufficiently full windows * 3/23/80 -- modified to decide buffering with fbufsiz() */ _fget(sp, buffer, length) register struct _stream *sp; t_byte *buffer; { register struct _file *fp; struct _stream *_wfill(); struct _window *_switch(); fp = sp->_sfile; if (fp == NULL) return(-1); if ((fp->_fflags & _IOREAD) == 0) return(-1); if ((fp->_fflags & (_IOBUF|_IONBF)) == 0) fbufsiz (sp); if (fp->_fflags & _IOBUF) { register t_byte *np; if (_switch(sp) == NULL) { sp->_sflags |= _IOFAIL; return(-1); } np = sp->_iopos + length; if (np > sp->_endata) { if (_wfill(sp) == NULL) return(-1); if (np > sp->_endata) { sp->_sflags |= _IOEOF; return(-1); } } return(1); } else { register int cnt; cnt = _fread(fp, buffer, length, sp->_sfaddr); if (cnt < 0) { sp->_sflags |= _IOFAIL; return(-1); } sp->_sfaddr += cnt; if (cnt < length) { sp->_sflags |= _IOEOF; return(-1); } return(0); } } _qU 4 I4/pitt/fgetc.cb#include /* * Return the next character in the argument I/O stream. * If the stream is not connected to the window that contains * this character, invoke _fget() to do the "appropriate thing". * Return EOF if _fget() fails. * * Daniel R. Strick * * 7/4/79 -- written * 7/11/79 -- rewritten * 7/12/79 -- tested */ fgetc(sp) register struct _stream *sp; { register rcode; char c; if (sp->_iopos >= sp->_endata) { rcode = _fget(sp, (t_byte *) &c, 1); if (rcode < 0) return(EOF); if (rcode == 0) return(c & 0377); } return(*sp->_iopos++ & 0377); } tqT 44/pitt/fgets.cb#include char * fgets(s, n, iop) char *s; register FILE *iop; { register c; register char *cs; cs = s; while (--n>0 && (c = getc(iop))>=0) { *cs++ = c; if (c=='\n') break; } if (c<0 && cs==s) return(NULL); *cs++ = '\0'; return(s); } qS 4M'!4/pitt/filbuf.cstatic char botch1[] = "\nYou are using old standard I/O calls with the new library!\n"; static char botch2[] = "\nNo main program!\n"; _oldcal() { write (2, botch1, sizeof botch1); } _filbuf() { _oldcall(); } _flsbuf() { _oldcal(); } main() { write (2, botch2, sizeof botch2); } qR 4[4/pitt/fopen.c#include FILE * fopen(file, mode) char *file; char *mode; { FILE *_fopen(); return(_fopen(file, mode, (FILE *) NULL)); } ;qQ 4Q4/pitt/fopensub.c#include #include #define EOS '\0' #define pair(a,b) (a + (b << 8)) /* * Obtain the requested access to the argument file and * create and I/O stream for it with _fdopen(). * Return a pointer to the created I/O stream. * Return NULL if something goes wrong. * * Daniel R. Strick * * 7/5/79 -- written * 7/9/79 -- tested */ FILE * _fopen(file, mode, stream) register char *file; register char *mode; FILE *stream; { register fd; long lseek(); FILE *_fdopen(); extern int errno; if (mode[1] != EOS && mode[2] != EOS) return(NULL); switch (pair(mode[0], mode[1])) { case pair('r', EOS): fd = open(file,0); break; case pair('w', EOS): fd = creat(file, 0666); break; case pair('r', 'w'): fd = open(file, 2); break; case pair('a', EOS): fd = open(file, 1); if (fd < 0 && errno == ENOENT) fd = creat(file, 0666); lseek(fd, 0L, 2); break; default: return(NULL); } if (fd < 0) return(NULL); return(_fdopen(fd, mode, stream)); } nqP 4]b4/pitt/fperror.c#include fperror(sp, tp) struct _stream *sp; char *tp; { register struct _file *fp; extern int errno; errno = 0; fp = sp->_sfile; if (fp != NULL && fp->_fflags & _IOERR) errno = fp->_ferrno; perror(tp); } ,qO 44/pitt/fprintf.c#include fprintf(iop, fmt, args) FILE *iop; char *fmt; { _doprnt(fmt, &args, iop); return(ferror(iop)? EOF: 0); } qN 4; 4/pitt/fput.c#include /* * This kludgy little routine is a collection of all those * things that the fputx() routines would have in common. * It is called when the fputx() routine discovers that * there is not enough room in the buffer described by * the _stream structure to put the data provided by its * caller. This routine will then do the "appropriate thing" * and return: * -1 -- if something went wrong and the caller should return * EOF, * 0 -- if the stream turned out not to be buffered and the * desired data was written directly from the argument * buffer, or * 1 -- if the the stream was buffered and the stream was * reconnected to the correct window. * * The "appropriate thing" is to make sure that the stream * is associated with a file that has write access, to decide * if the stream is buffered, and either connect the stream * to the correct window or write the data directly into the * file. * If the file is buffered and the stream is connected to * the correct window: * If the window is not open as far as the * location to be modified, try to fill it. * If it is still not open far enough, open * it wider by filling with zeroes. * Set _IOMOD and clear the trap that insures * that _IOMOD gets set if the window is poked. * Clear _IOSEEK to indicate that the current * stream position is NOT past the filled part * of the window buffer. * * * Daniel R. Strick * * 7/11/79 -- written * 7/12/79 -- tested * 3/20/80 -- modified to attempt to fill insufficiently full windows * 3/23/80 -- modified to decide buffering with fbufsiz() */ _fput(sp, buffer, length) register struct _stream *sp; t_byte *buffer; { register struct _file *fp; struct _stream *_wfill(); struct _window *_switch(); fp = sp->_sfile; if (fp == NULL) return(-1); if ((fp->_fflags & _IOWRT) == 0) return(-1); if ((fp->_fflags & (_IOBUF|_IONBF)) == 0) fbufsiz (sp); if (fp->_fflags & _IOBUF) { register struct _window *wp; if ((wp = _switch(sp)) == NULL) { sp->_sflags |= _IOFAIL; return(-1); } if (wp->_endata < sp->_iopos) { if (_wfill(sp) == NULL) return(-1); while (wp->_endata < sp->_iopos) *wp->_endata++ = 0; } sp->_endata = wp->_endata; sp->_endbuf = wp->_endbuf; sp->_sflags &= ~_IOSEEK; wp->_wflags |= _IOMOD; return(1); } else { register int cnt; cnt = _fwrite(fp, buffer, length, sp->_sfaddr); if (cnt != length) { sp->_sflags |= _IOFAIL; return(-1); } sp->_sfaddr += cnt; return(0); } } qM 4l4/pitt/fputc.cc#include /* * Put the argument character into the argument I/O stream * and return the character. * If the character does not go into the current file window, * invoke _fput() to do the "appropriate thing". * Return EOF if _fput() fails. * * Daniel R. Strick * * 7/4/79 -- written * 7/11/79 -- rewritten * 7/12/79 -- tested * 2/9/80 -- changed "_endata" to "_endbuf", curing an ulcer */ fputc(c, sp) register struct _stream *sp; { register rcode; if (sp->_iopos >= sp->_endbuf) { rcode = _fput(sp, (t_byte *) &c, 1); if (rcode < 0) return(EOF); if (rcode == 0) return(c); } *sp->_iopos++ = c; return(c); } qL 44/pitt/fputs.cc#include fputs(s, iop) register char *s; register FILE *iop; { register r; register c; while (c = *s++) r = putc(c, iop); return(r); } uqK 44/pitt/freopen.c#include FILE * freopen(file, mode, stream) char *file; char *mode; FILE *stream; { FILE *_fopen(); if (fclose(stream)) return(NULL); return(_fopen(file, mode, stream)); } )qJ 44/pitt/fsalloc.c#include /* * Find the first _stream structure that is not in use * and initialize it as a new stream: all pointers are * set to NULL, the file address is set to zero, and * the flags are cleared. * Return a pointer to this stream. * Return NULL if all streams are active. * Note that the activity flag in the allocated * stream is not set. * * Daniel R. Strick * * 7/9/79 -- written * 7/12/79 -- tested */ struct _stream * _fsalloc() { register struct _stream *sp; for (sp = &_iostrm[0]; sp < &_iostrm[_NSTRM]; ++sp) if ((sp->_sflags & _IOSUSE) == 0) { sp->_iopos = NULL; sp->_endata = NULL; sp->_endbuf = NULL; sp->_swndw = NULL; sp->_nxstrm = NULL; sp->_sfile = NULL; sp->_sfaddr = 0; sp->_sflags = 0; return(sp); } return(NULL); } iqI 4?4/pitt/fscratch.c#include /* * Use the system routine mktemp() to replace the argument * filename with the name of a nonexistant file. * Create this file, close it, and reopen it for both * read and write access. * If the file is to be invisible, unlink it immediately. * Return the I/O stream with read/write access. */ FILE * fscratch(name, visible) register char *name; { register FILE *file; char *mktemp(); file = fopen(mktemp(name), "w"); if (file == NULL) return(file); fclose(file); file = fopen(name, "rw"); if (!visible) unlink(name); return(file); } pqH 4PO 4/pitt/fseek.c.#include /* * Set the file position of the argument I/O stream * and return -1 if an error is detected, 0 otherwise. * If the stream is connected to the window that contains * the new file position, the stream's position within * the window is modified, the stream end-of-data pointer * is updated, and the _IOSEEK flag is set if the new * stream position is past the filled data area. * If the desired window is not quite so easy to find, * the stream is disconnected from its window (if connected), * and the new file address is saved in the stream structure. * * If a seek is attempted to anything other than absolute * address 0, the fancy buffering flag _IOFBF is set. * * Daniel R. Strick * * 7/10/79 -- written * ??????? -- tested * 7/10/79 -- modified to update eod pointer and set _IOSEEK * 7/12/79 -- modified to set _IOFBF * 4/7/80 -- modified to return an error flag (0 or -1) * instead of the previous file address * 4/8/80 -- parenthesized an expression to avoid a PDP-11 compiler bug */ fseek(sp, offset, ptrname) register struct _stream *sp; long offset; { register struct _window *wp; register struct _file *fp; register t_faddr newfaddr; register t_faddr oldfaddr; long lseek(); fp = sp->_sfile; newfaddr = offset; if (newfaddr != 0 || ptrname != 0) fp->_fflags |= _IOFBF; if (ptrname == 2) { fflush(sp); newfaddr = lseek(fp->_fildes, (long) newfaddr, 2); if (newfaddr < 0) return (-1); fp->_ffaddr = newfaddr; } wp = sp->_swndw; if (wp != NULL) { register t_faddr woff; oldfaddr = wp->_wfaddr + (sp->_iopos - wp->_bfbase); if (ptrname == 1) newfaddr += oldfaddr; woff = newfaddr - wp->_wfaddr; if (woff >= 0 && woff < wp->_endbuf - wp->_bfbase) { _upfill(sp); sp->_iopos = wp->_bfbase + woff; if (sp->_iopos > wp->_endata) { sp->_endbuf = wp->_bfbase; sp->_sflags |= _IOSEEK; } return(0); } _detach(sp); } else { oldfaddr = sp->_sfaddr; if (ptrname == 1) newfaddr += oldfaddr; } sp->_sfaddr = newfaddr; return(0); } tqG 4P4/pitt/ftell.c.#include /* * Return the position (file address) * of the argument I/O stream. * * Daniel R. Strick * * 7/4/79 -- written * ?????? -- tested * 4/8/80 -- parenthesized an expression to avoid a PDP-11 compiler bug */ long ftell(sp) register struct _stream *sp; { register struct _window *wp; if ((wp = sp->_swndw) == 0) return (sp->_sfaddr); return (wp->_wfaddr + (sp->_iopos - wp->_bfbase)); } qF 49x4/pitt/fwipe.c.#include /* * Clear all windows into the file accessed by the argument * I/O stream. If the I/O stream is currently connected * to a window, reposition the stream to the beginning * of the window. This routine is intended to be used * to cancel pending output to a terminal after an interrupt. * The effects of calling this routine at interrupt level * or in situations where there are multiple windows or * streams connected to the same file have not even been * considered. * * Daniel R. Strick * * 2/24/80 -- written * ??????? -- tested */ fwipe(sp) register struct _stream *sp; { register struct _window *wp; for (wp = sp->_sfile->_nxwndw; wp != NULL; wp = wp->_nxwndw) { wp->_endata = wp->_bfbase; wp->_wflags = 0; } wp = sp->_swndw; if (wp == NULL) return; sp->_iopos = sp->_endata = sp->_endbuf = wp->_bfbase; sp->_sflags &= ~_IOSEEK; } qE 44/pitt/gcvt.c/* * gcvt - Floating output conversion to * minimal length string */ char *ecvt(); char * gcvt(number, ndigit, buf) double number; char *buf; { int sign, decpt; register char *p1, *p2; register 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 #undef getchar getchar() { return(getc(stdin)); } 2qC 44/pitt/getgrent.c#include #include #define CL ':' #define CM ',' #define NL '\n' #define MAXGRP 100 static char GROUP[] = "/etc/group"; static FILE *grf = NULL; static char line[BUFSIZ+1]; static struct group group; static char *gr_mem[MAXGRP]; setgrent() { if( !grf ) grf = fopen( GROUP, "r" ); else rewind( grf ); } endgrent() { if( grf ){ fclose( grf ); grf = NULL; } } static char * grskip(p,c) register char *p; register 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, BUFSIZ, grf )) ) return(NULL); group.gr_name = p; group.gr_passwd = p = grskip(p,CL); group.gr_gid = atoi( p = grskip(p,CL) ); group.gr_mem = gr_mem; p = grskip(p,CL); grskip(p,NL); q = gr_mem; while( *p ){ *q++ = p; p = grskip(p,CM); } *q = NULL; return( &group ); } qB 44/pitt/getgrgid.c#include struct group * getgrgid(gid) register gid; { register struct group *p; struct group *getgrent(); setgrent(); while( (p = getgrent()) && p->gr_gid != gid ); endgrent(); return(p); } qA 44/pitt/getgrnam.c#include struct group * getgrnam(name) register char *name; { register struct group *p; struct group *getgrent(); setgrent(); while( (p = getgrent()) && strcmp(p->gr_name,name) ); endgrent(); return(p); } pq@ 44/pitt/getpass.c#include #include #include char * getpass(prompt) char *prompt; { struct sgttyb ttyb; int flags; register char *p; register c; FILE *fi; static char pbuf[9]; int (*signal())(); int (*sig)(); if ((fi = fopen("/dev/tty", "r")) == NULL) fi = stdin; else setbuf(fi, (char *)NULL); sig = signal(SIGINT, SIG_IGN); gtty(fileno(fi), &ttyb); flags = ttyb.sg_flags; ttyb.sg_flags &= ~ECHO; stty(fileno(fi), &ttyb); fprintf(stderr, prompt); for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) { if (p < &pbuf[8]) *p++ = c; } *p = '\0'; fprintf(stderr, "\n"); ttyb.sg_flags = flags; stty(fileno(fi), &ttyb); signal(SIGINT, sig); if (fi != stdin) fclose(fi); return(pbuf); } )q? 4$4/pitt/getpw.cc#include getpw(uid, buf) int uid; char buf[]; { static FILE *pwf; register n, c; register char *bp; if(pwf == 0) pwf = fopen("/etc/passwd", "r"); if(pwf == NULL) return(1); rewind(pwf); for (;;) { bp = buf; while((c=getc(pwf)) != '\n') { if(c == EOF) return(1); *bp++ = c; } *bp++ = '\0'; bp = buf; n = 3; while(--n) while((c = *bp++) != ':') if(c == '\n') return(1); while((c = *bp++) != ':') { if(c<'0' || c>'9') continue; n = n*10+c-'0'; } if(n == uid) return(0); } } q> 44/pitt/getpwent.c#include #include static char PASSWD[] = "/etc/passwd"; static char EMPTY[] = ""; static FILE *pwf = NULL; static char line[BUFSIZ+1]; static struct passwd passwd; setpwent() { if( pwf == NULL ) pwf = fopen( PASSWD, "r" ); else rewind( pwf ); } endpwent() { if( pwf != NULL ){ fclose( pwf ); pwf = NULL; } } static char * pwskip(p) register char *p; { while( *p && *p != ':' ) ++p; if( *p ) *p++ = 0; return(p); } struct passwd * getpwent() { register char *p; if (pwf == NULL) { if( (pwf = fopen( PASSWD, "r" )) == NULL ) return(0); } p = fgets(line, BUFSIZ, pwf); if (p==NULL) return(0); passwd.pw_name = p; p = pwskip(p); passwd.pw_passwd = p; p = pwskip(p); passwd.pw_uid = atoi(p); p = pwskip(p); passwd.pw_gid = atoi(p); passwd.pw_quota = 0; passwd.pw_comment = EMPTY; p = pwskip(p); passwd.pw_gecos = p; p = pwskip(p); passwd.pw_dir = p; p = pwskip(p); passwd.pw_shell = p; while(*p && *p != '\n') p++; *p = '\0'; return(&passwd); } pq= 44/pitt/getpwnam.c#include struct passwd * getpwnam(name) char *name; { register struct passwd *p; struct passwd *getpwent(); setpwent(); while( (p = getpwent()) && strcmp(name,p->pw_name) ); endpwent(); return(p); } pq< 44/pitt/getpwuid.c#include struct passwd * getpwuid(uid) register uid; { register struct passwd *p; struct passwd *getpwent(); setpwent(); while( (p = getpwent()) && p->pw_uid != uid ); endpwent(); return(p); } pq; 44/pitt/gets.c#include char * gets(s) char *s; { register c; register char *cs; cs = s; while ((c = getchar()) != '\n' && c >= 0) *cs++ = c; if (c<0 && cs==s) return(NULL); *cs++ = '\0'; return(s); } pq4 4;4/pitt/makebuf.c#include /* * Create a window for the argument stream * and return the argument stream pointer. * Return NULL if window creation fails. * Creating a window for an unbuffered stream * causes it to become buffered. * Creating extra windows for a file causes * fancy buffering. * * If the argument buffer pointer is not NULL, * storage at that location will be used for * the new window buffer. Routine fbufsiz() * may be used to find out how big the buffer * will be. * Routine setbuff() is intended to be used only * when a magnificent reduction in program size * results from overlaying buffers and some other * data structure. Normal applications should * use makebuf(). * * Daniel R. Strick * * 7/12/79 -- written * ??????? -- tested * 3/23/80 -- modified to set _IOBUF before calling _makwin() * 3/23/80 -- added the buffer pointer parameter and separated * makebuf() from setbuf() */ struct _stream * setbuff (sp, bufp) register struct _stream *sp; t_byte *bufp; { register struct _file *fp; struct _window *_makwin(); fp = sp->_sfile; fp->_fflags &= ~_IONBF; fp->_fflags |= _IOBUF; if (_makwin(sp, bufp) == NULL) return(NULL); if (fp->_nxwndw->_nxwndw != NULL) fp->_fflags |= _IOFBF; return(sp); } /* * Makebuf() is like setbuff() except that the buffer * address may not be specified. A buffer is really * a strange data type used only by the internal I/O * library routines. Most programs have no excuse for * fooling with the buffer data type and can avoid it * by using makebuf() instead of setbuff() or setbuf(). */ struct _stream * makebuf (sp) struct _stream *sp; { return (setbuff (sp, (t_byte *) NULL)); } (q3 54/pitt/popen.cc#include #include #define tst(a,b) (*mode == 'r'? (b) : (a)) #define RDR 0 #define WTR 1 static int popen_pid[20]; FILE * popen(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); dup2(hisside, tst(0, 1)); close(hisside); execl("/bin/sh", "sh", "-c", cmd, 0); _exit(1); } if(pid == -1) return NULL; popen_pid[myside] = pid; close(hisside); return(fdopen(myside, mode)); } pclose(ptr) FILE *ptr; { register f, r, (*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, istat); signal(SIGQUIT, qstat); signal(SIGHUP, hstat); return(status); } q2 5t4/pitt/printf.c#include printf(fmt, args) char *fmt; { _doprnt(fmt, &args, stdout); return(ferror(stdout)? EOF: 0); } q1 54/pitt/putchar.c/* * A subroutine version of the macro putchar */ #include #undef putchar putchar(c) register c; { putc(c, stdout); } tq0 5x4/pitt/puts.c#include puts(s) register char *s; { register c; while (c = *s++) putchar(c); return(putchar('\n')); } q# 5u4/pitt/rdwr.c#include fread(ptr, size, count, iop) unsigned size, count; register char *ptr; register FILE *iop; { register c; unsigned ndone, s; ndone = 0; if (size) for (; ndone= 0) *ptr++ = c; else return(ndone); } while (--s); } return(ndone); } fwrite(ptr, size, count, iop) unsigned size, count; register char *ptr; register FILE *iop; { register unsigned s; unsigned ndone; ndone = 0; if (size) for (; ndone rewind(sp) register FILE *sp; { fflush(sp); fseek(sp, 0L, 0); clearerr(sp); } eq7 54/pitt/scanf.cc#include scanf(fmt, args) char *fmt; int *args; { return(_doscan(stdin, fmt, &args)); } fscanf(iop, fmt, args) FILE *iop; char *fmt; int *args; { return(_doscan(iop, fmt, &args)); } sscanf(str, fmt, args) register char *str; char *fmt; int *args; { struct _stream _strbuf; _strbuf._iopos = _strbuf._endbuf = str; _strbuf._swndw = NULL; _strbuf._nxstrm = NULL; _strbuf._sfile = NULL; _strbuf._sfaddr = 0; _strbuf._sflags = 0; while (*str++); _strbuf._endata = str - 1; return(_doscan(&_strbuf, fmt, &args)); } nq6 5+<4/pitt/setbuf.c#include /* * Free all the windows into the file associated with * the argument I/O stream and create a single window * for it that uses the argument buffer space. * Make this file unbuffered if the argument buffer * pointer is NULL or window creation fails. * This routine exists only because the official * description of the standard I/O library says * that it exists. It might be useful if for * allocating buffer space in the stack but this * will cause nasty bugs if the stack goes away * before the window does. There is also the * possibility that the provided buffer space may * not be as large as the standard I/O routines think * it is; there should be no problem if all buffer * space is allocated automatically by _makwin. * Use makebuf() instead. * * Daniel R. Strick * * 7/9/79 -- written * 7/12/79 -- modified to reflect new buffering flags: _IOBUF, _IONBF * 7/12/79 -- tested */ setbuf(sp, buf) register struct _stream *sp; char *buf; { register struct _file *fp; register struct _window *wp; struct _window *_makwin(), *_nwfree(); fp = sp->_sfile; for (wp = (struct _window *) fp; wp->_nxwndw != NULL;) if (_nwfree(wp) == NULL) return; fp->_fflags &= ~(_IOBUF|_IONBF); if (buf == NULL || _makwin(sp, (t_byte *) buf) == NULL) { fp->_fflags |= _IONBF; return; } } q5 5NQS4/pitt/sprintf.c#include char * _sprntf (str, strend, fmt, argp) char *str, *strend; int *argp; { struct _stream _strbuf; _strbuf._iopos = _strbuf._endata = str; _strbuf._endbuf = (t_byte *) strend; _strbuf._swndw = NULL; _strbuf._nxstrm = NULL; _strbuf._sfile = NULL; _strbuf._sfaddr = 0; _strbuf._sflags = 0; _doprnt(fmt, argp, &_strbuf); if (putc('\0', &_strbuf) == EOF) { if (str < strend) strend[-1] = '\0'; return (NULL); } return(_strbuf._iopos-1); } char * sprintf (str, fmt, args) char *str, *fmt; { _sprntf (str, _MAXPNT, fmt, &args); return (str); } char * sprntfn (str, strend, fmt, args) char *str, *strend, *fmt; { return (_sprntf (str, strend, fmt, &args)); } eq4 5Pj14/pitt/stdio.cc#include /* * Make the end-of-data pointer in the window * referenced by with the argument stream reflect * additions made to the window through this stream. * Make the end-of-data pointer in this stream * reflect additions made through other streams. * * Daniel R. Strick * * 7/5/79 -- written * 7/12/79 -- tested * 7/12/79 -- modified to update stream end-of-data even if _IOSEEK set */ _upfill(sp) register struct _stream *sp; { register struct _window *wp; wp = sp->_swndw; if (wp == NULL) return; if (sp->_iopos > wp->_endata && (sp->_sflags&_IOSEEK) == 0) wp->_endata = sp->_iopos; sp->_endata = wp->_endata; } /* * Detach the argument stream from it's window. * The window is moved to the end of the list * of windows into the same file to achieve * some sort of clever caching effect if there * are more windows than streams and to encourage * management to buy a faster cpu. * * Daniel R. Strick * * 7/5/79 -- written * 7/12/79 -- tested */ _detach(sp) register struct _stream *sp; { register struct _window *wp, *wl; wp = sp->_swndw; if (wp == NULL) return; _upfill(sp); sp->_sfaddr = (sp->_iopos - wp->_bfbase) + wp->_wfaddr; sp->_iopos = NULL; sp->_endata = NULL; sp->_endbuf = NULL; sp->_swndw = NULL; for (wl = (struct _window *) sp->_sfile; ;wl = wl->_nxwndw) { if (wl->_nxwndw == wp) wl->_nxwndw = wp->_nxwndw; if (wl->_nxwndw == NULL) break; } wl->_nxwndw = wp; wp->_nxwndw = NULL; } /* * Return a pointer to the window into the * argument file that contains the argument * file address. * Return NULL if no window contains that location. * Return NULL if fancy buffering is not in effect. * * Daniel R. Strick * * 7/5/79 -- written * 7/12/79 -- tested * 3/21/80 -- modified to assume window file addresses are valid */ struct _window * _fafind(fp, faddr) register struct _file *fp; register t_faddr faddr; { register struct _window *wp; if ((fp->_fflags & _IOFBF) == 0) return(NULL); for (wp = fp->_nxwndw; wp != NULL; wp = wp->_nxwndw) if (faddr >= wp->_wfaddr && faddr < wp->_wfaddr + (wp->_endbuf - wp->_bfbase)) return(wp); return(NULL); } /* * Return a pointer to the first window in the * argument file's window list that is not referenced by * any stream. * Return NULL if all windows are in use. * * Daniel R. Strick * * 7/5/79 -- written * 7/12/79 -- tested */ struct _window * _choose(fp) register struct _file *fp; { register struct _window *wp; register struct _stream *sp; for (wp = fp->_nxwndw; wp != NULL; wp = wp->_nxwndw) { for (sp = fp->_nxstrm; ;sp = sp->_nxstrm) { if (sp == NULL) return(wp); if (sp->_swndw == wp) break; } } return(NULL); } /* * If the decision to buffer (or not to buffer) the * file accessed by the argument I/O stream has not * been made, make it now. The file is unbuffered if * it is the file used by the standard error I/O stream, * or if the it is the file used by the standard output * I/O stream and it is a tty special file. * * If the buffer size for the file has not yet been * established, set it now. Terminals get a buffer * size of 128 bytes. All other devices get a buffer * size of BUFSIZ bytes. * * If the file is buffered, return the buffer size. * If the file is not buffered, return 0. * * Daniel R. Strick * * 3/23/80 -- written */ fbufsiz (sp) register struct _stream *sp; { register struct _file *fp; fp = sp->_sfile; if (fp == NULL) return (0); if ((fp->_fflags & (_IOBUF|_IONBF)) == 0) { if (fp == stderr->_sfile || fp == stdout->_sfile && isatty (fp->_fildes)) fp->_fflags |= _IONBF; else fp->_fflags |= _IOBUF; } if (fp->_fflags & _IONBF) return (0); if (fp->_bufsiz == 0) { fp->_bufsiz = BUFSIZ; if (isatty (fp->_fildes)) fp->_bufsiz = 128; } return (fp->_bufsiz); } /* * Create an empty window and assign it * to the argument stream. * The new window is assigned the file * address -BUFSIZ (which will never * be used!). * Return a pointer to the new window. * Return NULL if window creation fails. * * Window creation fails if the storage * allocator balks. * * If the argument buffer pointer is not NULL, * malloc() is used to allocate storage only for * the window and the argument buffer is used * for the window buffer. This gimick is a * concession to setbuf(). * * Daniel R. Strick * * 7/5/79 -- written * 7/9/79 -- modified to accept the desired buffer address * 7/12/79 -- modified to assume that the file is buffered * 7/12/79 -- tested * 3/21/80 -- modified to assign address -fp->_bufsiz to new windows * 3/23/80 -- modified to set the file buffer size with fbufsiz() */ struct _window * _makwin(sp, buffer) register struct _stream *sp; t_byte *buffer; { register struct _file *fp; register struct _window *wp; register wbsize; char *malloc(); fp = sp->_sfile; if (fp == NULL) return(NULL); fbufsiz (sp); wbsize = sizeof *wp; if (buffer == NULL) wbsize += fp->_bufsiz; wp = (struct _window *) malloc(wbsize); if (wp == NULL) return(NULL); if ((wp->_bfbase = buffer) == NULL) wp->_bfbase = (t_byte *) (wp + 1); wp->_endata = wp->_bfbase; wp->_endbuf = wp->_bfbase + fp->_bufsiz; wp->_nxwndw = fp->_nxwndw; fp->_nxwndw = wp; wp->_wstrm = sp; wp->_wfile = fp; wp->_wfaddr = -fp->_bufsiz; wp->_wflags = 0; return(wp); } /* * Update the end-of-data pointer in the argument * window (and incidentally the end-of-data pointers * in all the windows into the same file) with _upfill(). * Note that not all of the end-of-data pointers in the * I/O streams are necessarily made current. * * Daniel R. Strick * * 7/5/79 -- written * 7/12/79 -- tested */ _extend(wp) struct _window *wp; { register struct _stream *sp; for (sp = wp->_wfile->_nxstrm; sp != NULL; sp = sp->_nxstrm) _upfill(sp); } /* * Write the contents of the argument buffer into * the argument file at the argument location. * A seek is done on the file only if this file * address is not the current file address stored * in the argument file structure. * The file address and the file size in the file * structure are updated appropriately. The file * address is set to -1 if an error occurs. * The value of this function is the number of bytes * written or -1 to indicate an error. * The number of bytes written is always the argument * length (which is supposedly > 0). * * Daniel R. Strick * * 7/5/79 -- written * 7/12/79 -- modified to return a byte count instead of the file pointer * 7/12/79 -- tested * 3/21/80 -- removed file size maintenance */ _fwrite(fp, buffer, length, faddr) register struct _file *fp; t_byte *buffer; register int length; register t_faddr faddr; { extern int errno; long lseek(); if (faddr != fp->_ffaddr) lseek(fp->_fildes, (long) faddr, 0); fp->_ffaddr = -1; if (write(fp->_fildes, buffer, length) != length) { fp->_fflags |= _IOERR; fp->_ferrno = errno; return(-1); } fp->_ffaddr = faddr + length; return(length); } /* * If the contents of the argument window have * been modified, update the file it opens into, * reset the output traps on all streams connected * to this window, and clear the modification * flag for this window (so that we don't have * to do this again). * The value of this function is the argument * window pointer or NULL to indicate an error. * * Daniel R. Strick * * 7/5/79 -- written * 7/10/79 -- modified to call _extend() only if window not full * 7/12/79 -- modified to accept byte transfer count from _fwrite * 7/12/79 -- tested */ struct _window * _wflush(wp) register struct _window *wp; { register struct _stream *sp; if (wp->_wflags & _IOMOD) { if (wp->_endata < wp->_endbuf) _extend(wp); if (_fwrite(wp->_wfile, wp->_bfbase, wp->_endata - wp->_bfbase, wp->_wfaddr) < 0) return(NULL); for (sp = wp->_wfile->_nxstrm; sp != NULL; sp = sp->_nxstrm) if (sp->_swndw == wp) sp->_endbuf = wp->_bfbase; wp->_wflags &= ~_IOMOD; } return(wp); } /* * Read the contents of the argument file at the * argument address into the argument buffer. * A seek is done on the file only if the desired * address is not the address stored in the file * structure. * The file address in the file structure is * set to the address of the first byte not * transferred. It is set to -1 if an error * occurs. * If the end of the file is encountered (if no * bytes are transferred by read()) at a location * less than the file size in the file structure, * the file size is set to this location. * The value of this function is the number of * bytes read or -1 to indicate an error. * * Daniel R. Strick * * 7/11/79 -- written * 7/12/79 -- tested * 7/12/79 -- added file size reduction after EOFs * 3/21/80 -- removed file size reduction after EOFs */ _fread(fp, buffer, length, faddr) register struct _file *fp; t_byte *buffer; register int length; register t_faddr faddr; { register cnt; extern int errno; long lseek(); if (faddr != fp->_ffaddr) lseek(fp->_fildes, (long) faddr, 0); fp->_ffaddr = -1; cnt = read(fp->_fildes, buffer, length); if (cnt < 0 || cnt > length) { fp->_fflags |= _IOERR; fp->_ferrno = errno; return(-1); } fp->_ffaddr = faddr + cnt; return(cnt); } /* * If the window buffer connected to the argument I/O stream * has been poked, make the end-of-data pointers in the window * and the stream up to date. * If the window buffer is not full and read access to the * associated file is permitted, try to fill the buffer with * data from the argument file and update the end-of-data * pointers accordingly. * Return the argument stream pointer. * Return NULL if a read error occurs. * * Daniel R. Strick * * 7/5/79 -- written * 7/10/79 -- modified to call _wflush() only if _IOMOD set * 7/11/79 -- modified to do reads with _fread() * 7/12/79 -- tested * 3/21/80 -- modified to fill the window with a vaild address * that is used by the argument stream rather than fill * the argument window with data at the argument file address */ struct _stream * _wfill(sp) register struct _stream *sp; { register struct _window *wp; register struct _file *fp; register rcnt; wp = sp->_swndw; if (wp == NULL) return (sp); if (wp->_wflags & _IOMOD) _extend (wp); sp->_endata = wp->_endata; fp = sp->_sfile; if ((fp->_fflags & _IOREAD) == 0 || wp->_endata >= wp->_endbuf) return(sp); rcnt = _fread(fp, wp->_endata, wp->_endbuf - wp->_endata, wp->_wfaddr + (wp->_endata - wp->_bfbase)); if (rcnt < 0) return(NULL); sp->_endata = (wp->_endata += rcnt); return(sp); } /* * Attach the argument stream to the argument window. * * Daniel R. Strick * * 7/6/79 -- written * 7/10/79 -- modified to clear _IOSEEK if not setting it * 7/12/79 -- tested * 4/8/80 -- parenthesized an expression to avoid a PDP-11 compiler bug */ _attach(sp, wp) register struct _stream *sp; register struct _window *wp; { sp->_iopos = wp->_bfbase + (sp->_sfaddr - wp->_wfaddr); sp->_sflags &= ~_IOSEEK; if (sp->_iopos > wp->_endata) sp->_sflags |= _IOSEEK; sp->_endata = wp->_endata; sp->_endbuf = wp->_bfbase; if ((wp->_wflags&_IOMOD) != 0 && (sp->_sflags&_IOSEEK) == 0) sp->_endbuf = wp->_endbuf; sp->_swndw = wp; } /* * Reconnect the argument I/O stream to a window that * contains the file location that it will next access. * Return a pointer to the new window. * Return NULL if an error occurs. * * Daniel R. Strick * * 7/5/79 -- written * 7/10/79 -- modified to call _extend() only if _IOMOD is set * 7/11/79 -- removed the file existance and access tests * 7/12/79 -- tested * 3/21/80 -- modified not to immediately fill the new window or * update the end-of-data pointers in the window or * the stream. */ struct _window * _switch(sp) register struct _stream *sp; { register struct _window *wp; register struct _file *fp; fp = sp->_sfile; wp = sp->_swndw; if (wp == NULL || sp->_iopos >= wp->_endbuf || (fp->_fflags&_IOFBF) == 0) { _detach(sp); wp = _fafind(fp, sp->_sfaddr); if (wp == NULL) { wp = _choose(fp); if (wp != NULL) { if (wp->_wfaddr >= 0) _wflush(wp); } else { wp = _makwin(sp, (t_byte *) NULL); if (wp == NULL) return(NULL); } wp->_endata = wp->_bfbase; wp->_wfaddr = (sp->_sfaddr / fp->_bufsiz) * fp->_bufsiz; if ((fp->_fflags & _IOFBF) == 0) wp->_wfaddr = sp->_sfaddr; wp->_wflags = 0; } _attach(sp, wp); } return(wp); } q3 <54/pitt/system.c#include system(s) char *s; { int status, pid, w; register int (*istat)(), (*qstat)(); if ((pid = fork()) == 0) { execl("/bin/sh", "sh", "-c", s, 0); _exit(127); } istat = signal(SIGINT, SIG_IGN); qstat = signal(SIGQUIT, SIG_IGN); while ((w = wait(&status)) != pid && w != -1) ; if (w == -1) status = -1; signal(SIGINT, istat); signal(SIGQUIT, qstat); return(status); } q2 +5e4/pitt/tmpnam.cchar *tmpnam(s) char *s; { static seed; sprintf(s, "temp.%d.%d", getpid(), seed++); return(s); } q :54/pitt/ungetc.c#include ungetc(c, sp) register struct _stream *sp; { register struct _window *wp; if (c == EOF) return(EOF); if ((wp = sp->_swndw) == NULL || sp->_iopos <= wp->_bfbase) return(EOF); *--sp->_iopos = c; return(0); } qAi\4/UKtqiD4/UK/information Here is U.K. software collected at Glasgow for inclusion in the Fourth Mailing. It originates from three centres, Queen Mary College, London, University of Kent at Canterbury, and University of Galsgow. Alistair Kilgour, 31st. Jan. 1978. qiD=84/UK/contents information contents setup_uk1 setup_qmc setup_kent setup_glasgow qmc/docs/man0/qmcbasinf qmc/docs/man0/qmcintro qmc/docs/man0/qmcprogs qmc/docs/man0/qmcptx qmc/docs/man0/qmctoc qmc/docs/man0/qmctocrc qmc/docs/man0 qmc/docs/man1/cont.a qmc/docs/man1/contents 8080asm.1 copy.1 cro.1 del.1 dir.1 em.1 fi.1 fs.1 help.1 ic.1 illus.1 intray.1 lexicon.1 link.1 linkr.1 lock.1 login.1 macro.1 mail.1 mas.1 mc.1 mermaid.1 news.1 nillus.1 odb.1 protect.1 roff.1 send.1 setup.1 spell.1 ter.1 unlock.1 who.1 qmc/docs/man1 qmc/docs/man2/terms.2 qmc/docs/man2 qmc/docs/man3/gterm.3 qmc/docs/man3/leave.3 qmc/docs/man3/sterm.3 qmc/docs/man3 qmc/docs/man4/tty.4 qmc/docs/man4 qmc/docs/man5/news.5 qmc/docs/man5/protocols.5 qmc/docs/man5/spdevices.5 qmc/docs/man5/tty.5 qmc/docs/man5/elog.5 qmc/docs/man5 qmc/docs/man6/bio.6 qmc/docs/man6/cal.6 qmc/docs/man6/chess.6 qmc/docs/man6/ml1.6 qmc/docs/man6/speak.6 qmc/docs/man6 qmc/docs/man7/heap.7 qmc/docs/man7/imlac.7 qmc/docs/man7/pop.7 qmc/docs/man7 qmc/docs/man8/lgn.8 qmc/docs/man8/zap.8 qmc/docs/man8 qmc/docs/em/emintro.n qmc/docs/em/tmac.M qmc/docs/em/emhelp/commands qmc/docs/em/emhelp/keys qmc/docs/em/emhelp/o qmc/docs/em/emhelp/reg qmc/docs/em/emhelp/s qmc/docs/em/emhelp qmc/docs/em qmc/docs/mas/mas qmc/docs/mas qmc/docs/mc/mc.n qmc/docs/mc qmc/docs/linkhelp qmc/docs/temp qmc/docs qmc/s1/cont.a qmc/s1/contents cal.c copy.c cro.c del dir dir.c em1.c em1.o em2.c em2.o fs getty.c help.c ic.c illus.c intray.c lgn.c link1.c link2.c login.c tt qmc/s1 qmc/s2/cont.a qmc/s2/contents mail.c mid.c msg.c news.c nillus.c opr.c send.c speak.c speakeng.v spell.c su.c who.c zap.c qmc/s2 qmc/8080asm/8080asm.h qmc/8080asm/asm1.c qmc/8080asm/asm2.c qmc/8080asm/asm3.c qmc/8080asm/asm4.c qmc/8080asm/asminit qmc/8080asm qmc/mas/cont.a qmc/mas/contents mas11.c mas12.c mas13.c mas14.c mas15.c mas16.c mas17.c mas1h.c mas21.c mas22.c mas23.c mas24.c mas25.c mas26.c mas27.c mas2h.c run setup qmc/mas qmc/mc/cont.a qmc/mc/contents mc.y mc0.c mc1.c mc2.c mc3.c mc4.c mc5.c mc6.c mc7.c mc8.c mch.c mch1.c run qmc/mc qmc/ml1/cont.a qmc/ml1/contents lowl.c makeml1 ml1_0.s ml1_1.s ml1_2.s ml1_3.s ml1_4.s ml1_5.s ml1_6.s ml1_c ml1_m.c qmc/ml1 qmc/imlac/graf.c qmc/imlac qmc/s4/gterm.c qmc/s4/callby.s qmc/s4/gterm.o qmc/s4 qmc/s5/sterm.c qmc/s5/terms.s qmc/s5/setbit.c qmc/s5/sterm.o qmc/s5/terms.o qmc/s5 qmc/odb/odb.doc qmc/odb/odb0.c qmc/odb/odb1.c qmc/odb/odb2.c qmc/odb/odb3.c qmc/odb/odb4.c qmc/odb/odb5.c qmc/odb/odb6.c qmc/odb/odb7.c qmc/odb/odb8.c qmc/odb/odb9.c qmc/odb/odbh0.c qmc/odb/run qmc/odb qmc/heap/cont.a qmc/heap/contents C_head check.c cons.c csv.s doheap.c dohpal.c donode.c fail.c flex.c free.c freeof.c genas.c getoff.c heap.c heapdoc.n hfail.c local.c run savall.c save.c signal.s stats.c trunc.c upb.c qmc/heap qmc/ttydriver/dmr/tty.c qmc/ttydriver/dmr/kl.c qmc/ttydriver/dmr qmc/ttydriver/tty.h qmc/ttydriver/proc.h qmc/ttydriver/user.h qmc/ttydriver/conf/m40.s qmc/ttydriver/conf qmc/ttydriver/ken/sysent.c qmc/ttydriver/ken qmc/ttydriver qmc/pop/doc/setup.n qmc/pop/doc qmc/pop/cont.a qmc/pop/contents distribmain.c dobrk.c doc dodisp.c doedit.c doprnt.s doread.c doscro.c dowrit.c main.c map.c menu.c pbord.c pbreak.c pclear.c pcline.c pclose.c pcoord.c pdisp.c pecho.c pedit.c pfdisp.c pfedit.c pfprnt.c pfputc.c pfread.c pfwrit.c pgetc.c pgetl.c pgmode.c pgtabs.c phome.c phseek.c pitt.c pmove.c pnoech.c pnoitt.c pnonu.c pnorm.c pop.h ppage.c pprnt.c pputc.c pread.c proll.c pscrol.c pshift.c psmode.c pstabs.c puser.c pvseek.c pwhere.c pwrit.c run screen.c qmc/pop/note qmc/pop qmc/games/fastermind.c qmc/games/hang.c qmc/games/hangman.c qmc/games/hrace.c qmc/games/oxo.c qmc/games/run qmc/games qmc/readme.r qmc/wilbur/mkconf.c qmc/wilbur/rx.c qmc/wilbur/build4.bell qmc/wilbur/getty.c qmc/wilbur/motd qmc/wilbur/passwd qmc/wilbur/m40.s qmc/wilbur/build5.qmc qmc/wilbur/build1.ucl qmc/wilbur/build3 qmc/wilbur/build2.qmc qmc/wilbur/ctime.c qmc/wilbur/build6 qmc/wilbur/news qmc/wilbur/dz.c qmc/wilbur/tty.c qmc/wilbur qmc/essex/dz.c qmc/essex qmc/bin/linkr qmc/bin/macro qmc/bin qmc/m11/cont.a qmc/m11/contents at.sml code.m11 exec.m11 expr.m11 fltg.m11 getl.m11 io.m11 linkr linkr.doc linkr.m11 lout.m11 mac.m11 maclnkbuild macro macro.doc macro.m11 misc.m11 psect.doc pst.m11 run srch.m11 sysmac.sml xlat.m11 xpcor.m11 qmc/m11 qmc kent/bcpl/source/note kent/bcpl/source/cont.a kent/bcpl/source/contents acg.bpl acg.c acghdr.bpl atbcpl.sml bcgen.c bcpl.c bcpl.doc btrace.m11 first.m11 llib.bpl llib.m11 maps.bpl maps.m11 master.bpl ntrn.bpl ocd.c sects.m11 shrsects.m11 stack.m11 synhdr.bpl sysmac.sml trnhdr.bpl tsyn.bpl users.doc kent/bcpl/source kent/bcpl/bclib/note kent/bcpl/bclib/cont.a kent/bcpl/bclib/contents acg atbcpl.sml bcpl btrace.obj dlib.hdr first.m11 first.obj ioerr.hdr iolib.m11 iolib.obj llib.obj maps.obj sects.m11 shrsects.obj stack.m11 stack.obj syshdr.bpl tlib.m11 tlib.obj kent/bcpl/bclib kent/bcpl/buildbcpl kent/bcpl/read.me.first kent/bcpl kent/man/man4/rx.4 kent/man/man4/tty.4 kent/man/man4 kent/man/man8/lpd.8 kent/man/man8/getty.8 kent/man/man8/archrun.8 kent/man/man8/icheck.8 kent/man/man8/inode.8 kent/man/man8/errdis.8 kent/man/man8/errlog.8 kent/man/man8/initdate.8 kent/man/man8/sa.8 kent/man/man8/proc1140.8 kent/man/man8 kent/man/man2/gtty.2 kent/man/man2/stty.2 kent/man/man2/terms.2 kent/man/man2 kent/man/index/uncom kent/man/index/tocrc kent/man/index/tocx1 kent/man/index/tocx5 kent/man/index/tocx168 kent/man/index/tocx8 kent/man/index/tocx6 kent/man/index/toc168 kent/man/index/uncmdcr kent/man/index/ptxun kent/man/index/unptx kent/man/index kent/man/man6/startrek.6 kent/man/man6 kent/man/man3/fptrap.3 kent/man/man3 kent/man/man7/ioinput.7 kent/man/man7/iomisc.7 kent/man/man7/iooutput.7 kent/man/man7 kent/man/man1/cont.a kent/man/man1/contents acg.1 arch.1 bcgen.1 bcpl.1 chdir.1 copy.1 dos.1 em.1 fastpr.1 fpsim.1 icp.1 killunix.1 lineno.1 linkr.1 list.1 lpkill.1 lpq.1 lpr.1 macro.1 mdb.1 newbin.1 next.1 ocd.1 off.1 pcp.1 prot.1 rmdir.1 rmff.1 rxcopy.1 rxinit.1 rxsh.1 set.1 sh.1 stabs.1 sten.1 stty.1 te.1 trace.1 unprot.1 wait.1 kent/man/man1 kent/man kent/macro/cont.a kent/macro/contents at.sml code.m11 exec.m11 expr.m11 fltg.m11 getl.m11 linkbuild linkr linkr.m11 lout.m11 mac.m11 macbuild macro macro.m11 misc.m11 pst.m11 srch.m11 sysmac.sml xlat.m11 xpcor.m11 kent/macro kent/rx/rxaddr.c kent/rx/rxcopy.c kent/rx/rxinit.c kent/rx/rxmedia.c kent/rx/rxrdaddr.c kent/rx/rxsh.c kent/rx/rx.c kent/rx/absblk.c kent/rx kent/ted/te1.bpl kent/ted/te2.bpl kent/ted/te3.bpl kent/ted/te4.bpl kent/ted/te.hdr kent/ted/stack.m11 kent/ted/first.m11 kent/ted/run kent/ted/mite.n kent/ted/oldte kent/ted kent/mdb/mdb2.c kent/mdb/mdb1.c kent/mdb kent/iolib/crew.c kent/iolib/read.me kent/iolib kent/local/cont.a kent/local/contents arch.c archrun.c copy.c dos.c err.c errdis.c errlog.c fastpr.c fpsim.c icp.c initdate.c inode.c intabs.c killunix.c koslink.c lineno.c link.c list.c off.c pcp.c proc1140.s prot.c rmcr.c rmff.c stabs.c sten.c stopu.o stopu.s trace.m11 tracebuild unprot.c kent/local kent/rkcopy kent/mods/em/em1.c kent/mods/em/em2.c kent/mods/em/emhelp kent/mods/em/emohlp kent/mods/em kent/mods/ctracer/tracer.c kent/mods/ctracer kent/mods/cont.a kent/mods/contents bio.c cc.c cct.c ctime.c ctracer em getty.c glob.c gsi.c icheck.c init.c login.c mkdir.c mkfs.c nohup.c pr.c pwd.c rk.c rm.c rmdir.c rp.c rx.c sa.c sh.c stty.c terms.s kent/mods kent/lpt/lpr.c kent/lpt/lpq.c kent/lpt/lpdexec.c kent/lpt/lpd.c kent/lpt/lpkill.c kent/lpt kent/disc.index kent/games/instructions kent/games/star.header kent/games/star1.c kent/games/star2.c kent/games/star3.c kent/games/star4.c kent/games/star5.c kent/games/star6.c kent/games/star8.c kent/games/star7.c kent/games/run kent/games kent/rt11/rtpip.c kent/rt11/rtun.c kent/rt11/run kent/rt11/rtclose.2 kent/rt11/rtdelete.2 kent/rt11/rtmount.2 kent/rt11/rtopen.2 kent/rt11/rtpip.1 kent/rt11/rtread.2 kent/rt11/rtumount.2 kent/rt11/rtwrite.2 kent/rt11 kent/ukciolib/run kent/ukciolib/man/doc.n kent/ukciolib/man/doc0 kent/ukciolib/man kent/ukciolib/cont.a kent/ukciolib/contents comps.c copys.c execut.s ffltpr.s fltpr.s getchar.s gets.c libu.a man printf.s rdnum.c readf.c readno.s rest.s run save.s selin.s selop.s system.s unget.s kent/ukciolib kent/docs/intro0 kent/docs/intro1 kent/docs/cdoc/cdoc1 kent/docs/cdoc/trac kent/docs/cdoc/cdoc0 kent/docs/cdoc/unixlicense kent/docs/cdoc/cdoc3 kent/docs/cdoc/cdoc2 kent/docs/cdoc kent/docs/amend/mhd kent/docs/amend/amend0 kent/docs/amend/amend1 kent/docs/amend/run kent/docs/amend kent/docs kent/mc/mc.y kent/mc/mg0.c kent/mc/mc2.c kent/mc/mc3.c kent/mc/mg4.c kent/mc/mc1.c kent/mc/mch.c kent/mc/mg3.c kent/mc/mc0.c kent/mc/mch1.c kent/mc/mg2.c kent/mc/mg1.c kent/mc/run kent/mc/mc2.s kent/mc/mc.doc kent/mc kent/ml1/lowl.c kent/ml1/ml1_0.s kent/ml1/ml1_1.s kent/ml1/ml1_2.s kent/ml1/ml1_3.s kent/ml1/ml1_4.s kent/ml1/ml1_5.s kent/ml1/ml1_6.s kent/ml1/ml1_c kent/ml1/ml1_m.c kent/ml1/run kent/ml1/ml1sig.r kent/ml1/ml1 kent/ml1/ml1.6 kent/ml1 kent/fp/read.n kent/fp/s3/atan.s kent/fp/s3/ecvt.s kent/fp/s3/exp.s kent/fp/s3/floor.s kent/fp/s3/fmod.s kent/fp/s3/fp.s kent/fp/s3/gamma.s kent/fp/s3/log.s kent/fp/s3/pow.s kent/fp/s3/sin.s kent/fp/s3/sqrt.s kent/fp/s3/test kent/fp/s3/e.s kent/fp/s3 kent/fp/commands/new.liba kent/fp/commands/fpsim kent/fp/commands/change.liba kent/fp/commands/new.libc kent/fp/commands/floatingc kent/fp/commands kent/fp/s4/fabs.s kent/fp/s4/abs.s kent/fp/s4/trap.fcrt0.s kent/fp/s4/atof.s kent/fp/s4/fcrt0.s kent/fp/s4/fltpr.s kent/fp/s4/ldfps.s kent/fp/s4/ltod.s kent/fp/s4/fmcrt0.s kent/fp/s4 kent/fp/s5/rin.c kent/fp/s5 kent/fp/read.me kent/fp/fort/f1/f12.s kent/fp/fort/f1/f11.s kent/fp/fort/f1 kent/fp/fort/f4/f46.s kent/fp/fort/f4/f45.s kent/fp/fort/f4/f41.s kent/fp/fort/f4 kent/fp/fort/fx/fx4.s kent/fp/fort/fx kent/fp/fort/io/io4.s kent/fp/fort/io/io6.s kent/fp/fort/io kent/fp/fort/rt/cont.a kent/fp/fort/rt/contents r0.s r3.s r5.s r6.s r7.s r9.s ra.s rc.s re.s rf.s rg.s rh.s kent/fp/fort/rt kent/fp/fort/rt1/cont.a kent/fp/fort/rt1/contents abs.s aimag.s aint.s alog.s alog10.s amax0.s amax1.s amin0.s amin1.s amod.s atan.s atan2.s cabs.s cexp.s cmplx.s conjg.s cos.s dim.s dimag.s exp.s iabs.s idim.s idint.s ierr.s isign.s mod.s real.s sign.s sin.s sqrt.s kent/fp/fort/rt1 kent/fp/fort/rt2/plot.s kent/fp/fort/rt2/ctime.s kent/fp/fort/rt2/rand.s kent/fp/fort/rt2 kent/fp/fort kent/fp/s1/fpsim.c kent/fp/s1 kent/fp kent glasgow/manmacs/tmac.an glasgow/manmacs/information glasgow/manmacs glasgow/s1/information glasgow/s1/doc/lstree.1 glasgow/s1/doc/cptree.1 glasgow/s1/doc/mkdir.1 glasgow/s1/doc/rm.1 glasgow/s1/doc/rmdir.1 glasgow/s1/doc/sh.1 glasgow/s1/doc/write.1 glasgow/s1/doc glasgow/s1/mkdir.c glasgow/s1/rmdir.c glasgow/s1/lstree glasgow/s1/cptree.c glasgow/s1/sh.c glasgow/s1/write.c glasgow/s1/rm.c glasgow/s1 glasgow/ref/information glasgow/ref/beg/part1.nroff glasgow/ref/beg/part2.nroff glasgow/ref/beg/copies glasgow/ref/beg glasgow/ref/cref/c.ref glasgow/ref/cref glasgow/ref/ctut/c.tut glasgow/ref/ctut glasgow/ref/edtut/ed.tut glasgow/ref/edtut glasgow/ref/refmacs/tmac.s glasgow/ref/refmacs glasgow/ref/lisp/l110.rof glasgow/ref/lisp/ed110.rof glasgow/ref/lisp glasgow/ref glasgow/spool/information glasgow/spool/qstate.c glasgow/spool/lpdaemon.c glasgow/spool/lpdaemon.h glasgow/spool/lp.c glasgow/spool/run glasgow/spool/sys/lp.c glasgow/spool/sys glasgow/spool/doc/opr.1 glasgow/spool/doc/lp.1 glasgow/spool/doc/qstate.1 glasgow/spool/doc/lp.4 glasgow/spool/doc/queues.5 glasgow/spool/doc/lpdaemon.8 glasgow/spool/doc glasgow/spool/opr.c glasgow/spool/killpid.c glasgow/spool/freesem.c glasgow/spool glasgow/sem/doc/semopen.3 glasgow/sem/doc/lock.3 glasgow/sem/doc/locked.3 glasgow/sem/doc/lockif.3 glasgow/sem/doc/unlock.3 glasgow/sem/doc/semaphores.5 glasgow/sem/doc glasgow/sem/semphr.c glasgow/sem/sys/sem.c glasgow/sem/sys/c.c glasgow/sem/sys/rdwri.c glasgow/sem/sys glasgow/sem/information glasgow/sem/ccasld glasgow/sem glasgow/sys/conf/copysys glasgow/sys/conf/m40.s glasgow/sys/conf/l.s glasgow/sys/conf/data.s glasgow/sys/conf/c.c.si glasgow/sys/conf/c.c.boot glasgow/sys/conf/ccasld.boot glasgow/sys/conf/ccasld.si glasgow/sys/conf glasgow/sys/run glasgow/sys/recompile glasgow/sys glasgow/lab/labeldisk.c glasgow/lab/mount.c glasgow/lab/whatdisk.c glasgow/lab/doc/mountfs.1 glasgow/lab/doc/unmount.1 glasgow/lab/doc/whatdisk.1 glasgow/lab/doc/disklabel.5 glasgow/lab/doc/labeldisk.8 glasgow/lab/doc glasgow/lab/checklabel.c glasgow/lab/label.h glasgow/lab/mountfs.c glasgow/lab/information glasgow/lab/sys3.c glasgow/lab/unmount.c glasgow/lab/ccasld glasgow/lab glasgow/disk/information glasgow/disk/si.h glasgow/disk/si.c glasgow/disk/rk.c glasgow/disk/rk.h glasgow/disk/disk.c glasgow/disk/disk.h glasgow/disk glasgow/s8/doc/icheck.8 glasgow/s8/doc/init.8 glasgow/s8/doc/mkfs.8 glasgow/s8/doc/glob.8 glasgow/s8/doc/newuser.8 glasgow/s8/doc/fastdown.8 glasgow/s8/doc/single.8 glasgow/s8/doc/diskcp.8 glasgow/s8/doc/diskcmp.8 glasgow/s8/doc/shutdown.1 glasgow/s8/doc glasgow/s8/init.c glasgow/s8/login.c glasgow/s8/mkfs.c glasgow/s8/glob.c glasgow/s8/newuser.c glasgow/s8/rkcmp.c glasgow/s8/rkcp.c glasgow/s8/killsubs.c glasgow/s8/information glasgow/s8/shutdown.c glasgow/s8/fastdown.c glasgow/s8/single.c glasgow/s8/diskcp.c glasgow/s8/diskcmp.c glasgow/s8 glasgow/tty/login.c glasgow/tty/ccasld glasgow/tty/thisisa glasgow/tty/gtty.s glasgow/tty/stty.s glasgow/tty/ttyn.s glasgow/tty/information glasgow/tty/sysent.c glasgow/tty/terms.s glasgow/tty/getty.c glasgow/tty/stty.c glasgow/tty/sys/m40.s glasgow/tty/sys/tty.c glasgow/tty/sys/tty.h glasgow/tty/sys/dh.c glasgow/tty/sys/dhdm.c glasgow/tty/sys/kl.c glasgow/tty/sys glasgow/tty/doc/tty.1 glasgow/tty/doc/stty.1 glasgow/tty/doc/thisisa.1 glasgow/tty/doc/stty.2 glasgow/tty/doc/terms.2 glasgow/tty/doc/gtty.2 glasgow/tty/doc/tty.4 glasgow/tty/doc/getty.8 glasgow/tty/doc/ttyn.3 glasgow/tty/doc glasgow/tty glasgow/information glasgow /q iD#4/UK/setup_uk1nsetup_qmc setup_kent setup_glasgow gq iD4/UK/setup_qmcnmkdir qmc chdir qmc : mkdir docs chdir docs mkdir man0 mkdir man1 mkdir man2 mkdir man3 mkdir man4 mkdir man5 mkdir man6 mkdir man7 mkdir man8 mkdir em mkdir mas mkdir mc chdir .. : mkdir s1 mkdir s2 mkdir 8080asm mkdir mas mkdir mc mkdir ml1 mkdir imlac mkdir s4 mkdir s5 mkdir odb mkdir heap : mkdir ttydriver chdir ttydriver mkdir dmr mkdir conf mkdir ken chdir .. : mkdir pop chdir pop mkdir doc chdir .. : mkdir games mkdir wilbur mkdir essex mkdir bin mkdir m11 : chdir .. /q iD4/UK/setup_kentmkdir kent chdir kent : mkdir bcpl chdir bcpl mkdir source mkdir bclib chdir .. : mkdir mas : mkdir man chdir man mkdir man1 mkdir man2 mkdir man3 mkdir man4 mkdir man6 mkdir man7 mkdir man8 mkdir index chdir .. : mkdir macro mkdir rx mkdir ted mkdir mdb mkdir iolib mkdir local mkdir rkcopy : mkdir mods chdir mods mkdir em mkdir ctracer chdir .. : mkdir lpt mkdir games mkdir rt11 : mkdir ukciolib chdir ukciolib mkdir man chdir .. : mkdir docs chdir docs mkdir cdoc mkdir amend chdir .. : mkdir mc mkdir ml1 : mkdir fp chdir fp mkdir s1 mkdir s3 mkdir s4 mkdir s5 mkdir commands : : mkdir fort chdir fort mkdir f1 mkdir f4 mkdir fx mkdir io mkdir rt mkdir rt1 mkdir rt2 chdir .. : : chdir .. : : chdir .. q iD4/UK/setup_glasgowimkdir glasgow chdir glasgow : mkdir s1 chdir s1 mkdir doc chdir .. : mkdir s8 chdir s8 mkdir doc chdir .. : mkdir disk : mkdir ref chdir ref mkdir beg mkdir cref mkdir ctut mkdir edtut mkdir refmacs chdir .. : mkdir spool chdir spool mkdir sys mkdir doc chdir .. : mkdir sys chdir sys mkdir conf chdir .. : mkdir lab chdir lab mkdir doc chdir .. : mkdir tty chdir tty mkdir sys mkdir doc chdir .. : chdir .. qA i\r 4/UK/glasgowaqAj\4/UK/glasgow/diskq jD4/UK/glasgow/disk/disk.c# /* * These routines handle the data structures of the GUCS disk * handlers. They are called by the specific device handlers. */ #include "../param.h" #include "../buf.h" #include "../user.h" #include "../conf.h" #include "../disk.h" /* * The strategy routine validates the request, and then inserts it * into the doubly linked list of requests for the logical disk. */ diskstrategy( pdp, aldp, abp) struct pdisk *pdp; struct ldisk *aldp; struct buf *abp; { register struct buf *bp, *p; register struct ldisk *ldp; bp = abp; ldp = aldp; bp->b_resid = 0; if ( bp->b_blkno + (-bp->b_wcount+255)/256 > ldp->l_nblk ) bp->b_flags =| B_ERROR; if ( bp->b_flags&B_ERROR ) { bp->b_error = ENXIO; bp->b_resid = -bp->b_wcount; iodone(bp); return; } spl5(); /* Put request in I/O queue for ld, in blkno order */ for ( p= ldp->av_forw; p!= ldp && bp->b_blkno>p->b_blkno; p= p->av_forw ); /* insert bp in front of p */ p->av_back->av_forw = bp; bp->av_back = p->av_back; bp->av_forw = p; p->av_back = bp; /* Increment count of requests at this prio level */ (pdp->p_schedule +ldp->l_prio) ->s_reqcount++; spl0(); diskstart( pdp ); } /* * The start routine first checks if the physical device is busy. * If not it selects the next request for service and * initiates an overlapped seek. */ diskstart( apdp ) struct pdisk *apdp; { register struct pdisk *pdp; register struct prilev *prio; register char *p; struct buf *bp; struct ldisk *ldp; int sps; pdp = apdp; sps = PS->integ; spl5(); if ( pdp->p_flags&P_BUSY ) goto out; /* Find highest prio level with request waiting */ for ( prio= pdp->p_schedule; prio->s_reqcount ==0; prio++ ); if ( prio->s_reqcount < 0 ) /* list terminator => no requests */ goto out; prio->s_reqcount--; pdp->p_flags =| P_BUSY; PS->integ = sps; /* Find next request */ if ( (p=prio->s_nextbp) == 0 ) { /* Search order list for next disk waiting, * starting from where we left off last time */ for ( p= prio->s_order +prio->s_ordptr;; p++ ) { if ( *p == ',' ) /* change head direction */ prio->s_headdir = -prio->s_headdir; else if ( *p == ';' ) { /* back to the list head */ p = prio->s_order -1; /* incr. to s_order */ prio->s_headdir = 1; } else { ldp = &(pdp->p_ldisks)[*p]; if ( ldp->av_forw != ldp ) /* Got one */ break; } } /* Update the pointers to new position */ prio->s_ordptr = p - prio->s_order; prio->s_curldisk = ldp; /* from now on p points to bp - request chosen */ p = prio->s_headdir>0? ldp->av_forw: ldp->av_back; } else ldp = prio->s_curldisk; pdp->p_buf = p; pdp->p_ldp = ldp; /* Remove bp from I/O queue */ p->av_forw->av_back = p->av_back; p->av_back->av_forw = p->av_forw; /* Set the next bp, if none move to next ld */ bp = prio->s_headdir>0? p->av_forw: p->av_back; if ( bp == ldp ) { /* no more requests */ bp = 0; prio->s_ordptr++; } prio->s_nextbp = bp; (*pdp->p_start)(pdp); return; out: PS->integ = sps; } /* * Put the physical cylinder number in p_addr1, * and the number of residual blocks in p_addr2. */ diskflip( apdp, blkspercyl ) struct pdisk *apdp; int blkspercyl; { register struct pdisk *pdp; register struct buf *bp; register int n; int cyl; pdp = apdp; bp = pdp->p_buf; n = bp->b_blkno; /* Calculate the virtual cyl no, and remaining blocks */ cyl = ldiv( n, blkspercyl); pdp->p_addr2 = lrem( n, blkspercyl ); if ( pdp->p_ldp->l_flags &L_FLIPCYL ) { /* Map high cyl no to low cyl no and vice versa */ cyl = ldiv( pdp->p_ldp->l_nblk -1, blkspercyl) - cyl; /* A multiblock transfer may split over two cyls. * Put the words remaining to transfer in b_resid */ if ( pdp->p_addr2 + (-bp->b_wcount+255)/256 > blkspercyl ) { n = (pdp->p_addr2 - blkspercyl)*256; bp->b_resid = bp->b_wcount - n; bp->b_wcount = n; } } pdp->p_addr1 = pdp->p_ldp->l_locyl + cyl; } /* * Hand back request as completed. * Non-zero status implies request failed with error "status". */ diskfinish( adt, status, resid ) struct devtab *adt; int status, resid; { register struct buf *bp; register struct pdisk *pdp; register struct devtab *dt; dt = adt; pdp = dt->d_actf; bp = pdp->p_buf; /* Report errors */ diskerror( pdp ); pdp->p_errcnt = 0; pdp->p_errsprtd = 0; pdp->p_resid = 0; /* Remove from the r/w queue */ dt->d_actf = dt->d_actf->d_actf; if ( dt->d_actf == 0 ) dt->d_actl = dt; /* I/O error ? */ if ( status ) { bp->b_flags =| B_ERROR; bp->b_error = status; bp->b_resid =+ resid; } /* If request was split by diskflip, initiate * the rest of the transfer */ else if ( bp->b_resid ) { dpadd( &bp->b_xmem, (-bp->b_wcount)<<1 ); bp->b_blkno =- bp->b_wcount/256; bp->b_wcount = bp->b_resid; bp->b_resid = 0; (*pdp->p_start)(pdp); return; } pdp->p_flags =& ~P_BUSY; diskstart( pdp ); iodone( bp); } /* * Increment the error count for the transfer, and print * print the number of errors so far if required. */ diskfail( apdp, error, resid) struct pdisk *apdp; int error, resid; { register struct pdisk *pdp; pdp = apdp; if ( pdp->p_error !=error || pdp->p_resid !=resid ) diskerror( pdp); pdp->p_error = error; pdp->p_resid = resid; return( ++pdp->p_errcnt ); } /* * Report any un-reported errors on the transfer. */ diskerror( apdp ) struct pdisk *apdp; { register struct pdisk *pdp; register struct buf *bp; register int errs; int dev; pdp = apdp; bp = pdp->p_buf; errs = pdp->p_errcnt - pdp->p_errsprtd; if ( errs > 0 ) { dev = bp->b_dev; printf("SYSERR: %d of %o dev %d/%d @blk %d\n", errs, pdp->p_error, dev.d_major, dev.d_minor, bp->b_blkno +(pdp->p_resid -bp->b_wcount)/256 ); pdp->p_errsprtd = pdp->p_errcnt; } } q jD4/UK/glasgow/disk/disk.h/* * Each logical disk is defined by an ldisk structure. * This defines the address of the disk, and holds the head * and tail of the doubly linked I/O queue for the disk. */ struct ldisk { char l_flags; /* see defines below */ char l_prio; /* priority level of ldisk */ int l_locyl; /* starting cylinder address */ char *l_nblk; /* length in blocks */ struct buf *av_forw; /* head of I/O queue */ struct buf *av_back; /* tail " */ }; /* l_flags bits */ #define L_FLIPCYL 01 /* * Each logical disk has a priority level. The scheduling of requests * at each priority level is controlled by the prilev structure for * that priority level. The scheduling chooses a logical disk for service * and then works forwards or backwards through the requests on that disk * according to the head direction. The logical disk is chosen as the * next in *s_order with requests pending. */ struct prilev { int s_reqcount; /* no. requests waiting */ char s_ordptr; /* current postion in schedule list */ char s_headdir; /* head direction */ char *s_order; /* servicing order */ struct ldisk *s_curldisk; /* ldisk of current request */ struct buf *s_nextbp; /* scheduled for service next */ }; /* * Each physical disk is described by a pdisk structure. * This contains all the status information for the disk * while I/O is in progress on the disk. */ struct pdisk { /* The following refer to the request currently being serviced */ struct buf *p_buf; /* request's buf */ struct ldisk *p_ldp; /* its ldisk */ char p_errcnt; /* errors so far on request */ char p_errsprtd; /* errors reported so far */ struct buf *d_actf; /* linkage for q of disks to r/w */ int p_addr1; /* physical address 1 */ int p_addr2; /* " 2 */ int p_error; /* copy of error register at last error */ int p_resid; /* words remaining after I/O error */ /* Information about the disk */ char p_flags; /* see defines below */ char p_nldisks; /* no of logical disks on pdisk */ struct ldisk *p_ldisks; /* the logical disks on pdisk */ int (*p_start)(); /* the overlapped start routine */ struct prilev *p_schedule; /* head of list of priority levels */ }; /* p_flags bits */ #define P_BUSY 01 #define P_SEEKING 02 q jD4/UK/glasgow/disk/information This directory contains a handler for an S.I. disk controller (9502). Overlapped seek, i.e. simultaneous seek on one drive and read or write on the other is not permitted by this controller, but the driver is easily modified to handle overlapped seek if the controller is upgraded in the future. Also included is a new overlapped-seek RK handler. Both drivers use common routines contained in 'disk.c'. bq jDF 4/UK/glasgow/disk/rk.cm# /* * Glasgow RK disk handler */ #include "../param.h" #include "../buf.h" #include "../disk.h" #include "../conf.h" #include "../user.h" #include "rk.h" #define RKADDR 0177400 /* Number of retries on error */ #define ERRLIM 10 /* Control status register bits */ #define RESET 0 #define GO 01 #define IENABLE 0100 #define ERROR 0100000 /* Error register bits */ #define NXSECTOR 040 #define NXCYL 0100 #define NXDISK 0200 #define DATALATE 01000 #define WLOVIOLATE 020000 #define DRIVERROR 0100000 struct { int rk_dsr; int rk_er; int rk_csr; int rk_wcr; int rk_cbar; int rk_dar; }; struct devtab rktab; struct buf rrkbuf; int rk_init 1; /* Masks for decoding the minor dev no */ #define PORT 07 #define LDISK 017 /* Synonym for the first pdisk address field */ #define dar p_addr1 rkstrategy( abp ) struct buf *abp; { register struct buf *bp; register struct pdisk *pdp; register int drive; int ldisk; bp = abp; /* Check the minor dev no */ drive = bp->b_dev &PORT; ldisk = (bp->b_dev &LDISK) >>2; pdp = &rkdisks[drive]; if ( drive>= NRKDEV || ldisk>= pdp->p_nldisks ) bp->b_flags =| B_ERROR; diskstrategy( pdp, &(pdp->p_ldisks)[ldisk], bp ); } rkstart( apdp ) struct pdisk *apdp; { register struct pdisk *pdp; register int blk; pdp = apdp; diskflip( pdp, 24 ); blk = pdp->p_addr2; pdp->dar = (pdp->p_buf->b_dev &PORT)<<13 | (pdp->p_ldp->l_locyl +pdp->p_addr1)<<5 | (blk/12)<<4 | (blk%12); if ( rk_init ) { rk_init = 0; RKADDR->rk_csr = RESET |GO; rktab.d_actl = &rktab; } /* Put it in the queue for a transfer */ rktab.d_actl->d_actf = pdp; rktab.d_actl = pdp; pdp->d_actf = 0; rkrwstart(); } rkrwstart() { register struct pdisk *pdp; register int sps; sps = PS->integ; spl5(); if ( rktab.d_active == 0 && (pdp= rktab.d_actf) != 0 ) { rktab.d_active++; devstart( pdp->p_buf, &RKADDR->rk_dar, pdp->dar, 0 ); } PS->integ = sps; } rkintr() { register struct pdisk *pdp; register int error, stat; if ( rktab.d_active == 0 ) return; rktab.d_active = 0; pdp = rktab.d_actf; stat = 0; if ( RKADDR->rk_csr &ERROR ) { error = RKADDR->rk_er; RKADDR->rk_csr = RESET |GO; if ( error &(DRIVERROR|NXDISK|NXCYL|NXSECTOR) ) stat = ENXIO; else if ( error &DATALATE || diskfail( pdp, error, RKADDR->rk_wcr ) < ERRLIM ) { rkrwstart(); return; } else stat = EIO; } diskfinish( &rktab, stat, RKADDR->rk_wcr ); rkrwstart(); } rkread( dev ) int dev; { physio( rkstrategy, &rrkbuf, dev, B_READ ); } rkwrite( dev ) int dev; { physio( rkstrategy, &rrkbuf, dev, B_WRITE ); } q jD0 4/UK/glasgow/disk/rk.hm /* * Data initialization for the RK handler */ #define NRKDEV 4 /* * * * * Port 0 * * * * */ struct ldisk rk0[] { /* Ldisk 0 */ 0 | /* flags */ ( 0 <<8), /* priority */ 0, /* lo cyl */ 4872, /* no of blocks */ &rk0[0], /* av_forw */ &rk0[0] /* av_back */ }; struct prilev rk0prio[] { /* Level 0 */ 0, /* request count */ 0 | /* order pointer */ ( 1 <<8), /* head direction */ rk_ord0, /* service order */ 0, /* current ldisk */ 0, /* next bp for service */ -1 /* Terminator */ }; /* * * * * Port 1 * * * * */ struct ldisk rk1[] { /* Ldisk 0 */ 0 | /* flags */ ( 0 <<8), /* priority */ 0, /* lo cyl */ 4872, /* no of blocks */ &rk1[0], /* av_forw */ &rk1[0] /* av_back */ }; struct prilev rk1prio[] { /* Level 0 */ 0, /* request count */ 0 | /* order pointer */ ( 1 <<8), /* head direction */ rk_ord0, /* service order */ 0, /* current ldisk */ 0, /* next bp for service */ -1 /* Terminator */ }; /* * * * * Port 2 * * * * */ struct ldisk rk2[] { /* Ldisk 0 */ 0 | /* flags */ ( 0 <<8), /* priority */ 0, /* lo cyl */ 4872, /* no of blocks */ &rk2[0], /* av_forw */ &rk2[0], /* av_back */ /* Ldisk 1 */ 0 | /* flags */ ( 0 <<8), /* priority */ 24, /* lo cyl */ 4056, /* no of blocks */ &rk2[1], /* av_forw */ &rk2[1], /* av_back */ /* Ldisk 2 */ 0 | /* flags */ ( 0 <<8), /* priority */ 0400, /* lo cyl, cyl 0 of drive 3 (nasty frig) */ 4872, /* no of blocks */ &rk2[2], /* av_forw */ &rk2[2] /* av_back */ }; struct prilev rk2prio[] { /* Level 0 */ 0, /* request count */ 0 | /* order pointer */ ( 1 <<8), /* head direction */ rk_ord0, /* service order */ 0, /* current ldisk */ 0, /* next bp for service */ /* Level 1 */ 0, /* request count */ 0 | /* order pointer */ ( 1 <<8), /* head direction */ rk_ord1, /* service order */ 0, /* current ldisk */ 0, /* next bp for service */ -1 /* Terminator */ }; char rk_ord0[] "\0,\0;" ; char rk_ord1[] "\1\2,\2,\2,\2\1;" ; /* * * * * Pdisks * * * * */ struct pdisk rkdisks[] { /* Pdisk 0 */ 0, /* current request */ 0, /* " ldisk */ 0 | /* error count */ ( 0 <<8), /* errors printed */ 0, /* r/w queue linkage */ 0, /* physical address 1 */ 0, /* physical address 2 */ 0, /* error register */ 0, /* words after error */ 0 | /* flags */ ( 1 <<8), /* no. of ldisks */ rk0, /* the ldisks */ &rkstart, /* seek start routine */ rk0prio, /* priority level structures */ /* Pdisk 1 */ 0, /* current request */ 0, /* " ldisk */ 0 | /* error count */ ( 0 <<8), /* errors printed */ 0, /* r/w queue linkage */ 0, /* physical address 1 */ 0, /* physical address 2 */ 0, /* error register */ 0, /* words after error */ 0 | /* flags */ ( 1 <<8), /* no. of ldisks */ rk1, /* the ldisks */ &rkstart, /* seek start routine */ rk1prio, /* priority level structures */ /* Pdisk 2 */ 0, /* current request */ 0, /* " ldisk */ 0 | /* error count */ ( 0 <<8), /* errors printed */ 0, /* r/w queue linkage */ 0, /* physical address 1 */ 0, /* physical address 2 */ 0, /* error register */ 0, /* words after error */ 0 |  /* flags */ ( 3 <<8), /* no. of ldisks */ rk2, /* the ldisks */ &rkstart, /* seek start routine */ rk2prio /* priority level structures */ }; q jD4/UK/glasgow/disk/si.cm# /* * Register proding routines for the SI disks, * to be used in conjunction with disk.c */ #include "../param.h" #include "../buf.h" #include "../conf.h" #include "../user.h" #include "../disk.h" #include "si.h" /* Control register bits */ #define GO 01 #define WRITE 02 #define READ 04 #define VERIFY 010 #define IENABLE 0100 #define DONE 0200 #define STROBENORMAL 0 #define STROBELATE 04000 #define STROBEARLY 010000 #define OFFSETNORMAL 0 #define OFFSETMINUS 020000 #define OFFSETPLUS 040000 /* Error register bits */ #define BADSECTOR 01000 #define DRIVEFAULT 04000 #define SELECTERROR 010000 #define RWERRORS 077770 /* Seek status error register bits */ #define DONEPORT0 016 struct { int si_cr; /* control register */ int si_wcr; /* word count register */ int si_pcar; /* port cylinder address register */ int si_hsar; /* head sector address register */ int si_mar; /* memory address register */ int si_er; /* error register */ int si_ssr; /* seek status register */ int si_sar; /* seek address register */ }; int SIADDR 0176700; struct devtab sitab; struct buf rsibuf; int si_init 1; int sirecovery[] { OFFSETNORMAL | STROBENORMAL, OFFSETMINUS | STROBENORMAL, OFFSETPLUS | STROBENORMAL, OFFSETNORMAL | STROBELATE, OFFSETMINUS | STROBELATE, OFFSETPLUS | STROBELATE, OFFSETNORMAL | STROBEARLY, OFFSETMINUS | STROBEARLY, OFFSETPLUS | STROBEARLY }; /* Synonyms for the pdisk address fields */ #define pcar p_addr1 #define hsar p_addr2 /* Masks for decoding the minor device no */ #define PORT 03 #define LDISK 0174 /* Clock ticks allowed before software interrupt forced */ #define SITIMEOUT 25 /* Limit of retry's on a transfer */ #define ERRLIM 5*9 sistrategy( abp) struct buf *abp; { register struct buf *bp; register struct pdisk *pdp; register int drive; int ldisk; bp = abp; /* Check that the minor dev no is ok */ drive = bp->b_dev &PORT; ldisk = (bp->b_dev &LDISK) >>2; pdp = &si_disks[drive]; if ( drive>= NSIDEV || ldisk>= pdp->p_nldisks ) bp->b_flags =| B_ERROR; diskstrategy( pdp, &(pdp->p_ldisks)[ldisk], bp); } sistart( apdp) struct pdisk *apdp; { register struct pdisk *pdp; register int sps; extern sisoftintr(); pdp = apdp; diskflip( pdp, 160 ); pdp->pcar = (pdp->p_buf->b_dev &PORT)<<10 | pdp->p_addr1; /* Arrange to do a LMC at startup */ if ( si_init ) { si_init = 0; SIADDR->si_cr = 0; /* Enable interrupts */ SIADDR->si_cr = IENABLE| READ; sitab.d_actl = &sitab; } /* Pretend we've done an overlapped seek */ sitab.d_actl->d_actf = pdp; sitab.d_actl = pdp; pdp->d_actf = 0; sps = PS->integ; spl5(); sirwstart(); PS->integ = sps; /* All of which is replaced by : pdp->p_flags =| P_SEEKING; SIADDR->si_sar = pdp->pcar; timeout( sisoftintr, 0, HZ/2 ); */ } sirwstart() { register struct pdisk *pdp; register struct buf *bp; extern sisoftintr(); if ( sitab.d_active ) return; /* Any disks in the r/w queue ? */ if ( (pdp= sitab.d_actf) == 0 ) return; sitab.d_active++; bp = pdp->p_buf; SIADDR->si_mar = bp->b_addr; SIADDR->si_hsar = pdp->hsar; SIADDR->si_pcar = pdp->pcar; SIADDR->si_wcr = -bp->b_wcount; SIADDR->si_cr = GO| IENABLE| (bp->b_xmem&03)<<4 | ( bp->b_flags&B_READ? READ: WRITE )| sirecovery[ pdp->p_errcnt %9 ]; timeout( sisoftintr, 0, HZ/2 ); } siintr() { register struct pdisk *pdp; register int stat, n; int wds; extern sisoftintr(); /* Re-enable interrupts */ SIADDR->si_cr = IENABLE |READ; wds = -~SIADDR->si_wcr; stat = SIADDR->si_ssr; killtimeouts( sisoftintr, 0 ); /* Detect completed seeks */ n = DONEPORT0; for ( pdp= si_disks; pdp< &si_disks[NSIDEV]; pdp++ ) { if ( pdp->p_flags&P_SEEKING && n&stat ) { /* Put him in the r/w queue */ sitab.d_actl->d_actf = pdp; sitab.d_actl = pdp; pdp->d_actf = 0; pdp->p_flags =& ~P_SEEKING; } n =<< 4; } if ( sitab.d_active ) { /* Get the r/w error bits of the error register */ n = SIADDR->si_er &RWERRORS; pdp = sitab.d_actf; sitab.d_active = 0; stat = 0; if ( n | sitab.d_errcnt ) { if ( n &(BADSECTOR|SELECTERROR|DRIVEFAULT) ) stat = ENXIO; else if ( diskfail( pdp, n, wds) < ERRLIM ) { /* Try again */ sirwstart(); return; } else stat = EIO; } diskfinish( &sitab, stat, wds ); } sirwstart(); } /* * Software interrupt, only happens when hardware error results * in no interrupt from the controller. */ sisoftintr( arg ) int arg; { /* Reset the controller, then do an interrupt */ SIADDR->si_cr = 0; sitab.d_errcnt++; siintr(); sitab.d_errcnt = 0; } siread( dev ) int dev; { physio( sistrategy, &rsibuf, dev, B_READ ); } siwrite( dev ) int dev; { physio( sistrategy, &rsibuf, dev, B_WRITE ); } }q jD4/UK/glasgow/disk/si.hm #define NSIDEV 2 /* Data declarations and intialization for the SI handler */ /* * * * * Port 0 * * * * */ struct ldisk si0[] { /* Ldisk 0 */ L_FLIPCYL | /* flags */ ( 1 <<8), /* priority */ 0, /* lo cyl */ 48800, /* no of blocks */ &si0[0], /* av_forw */ &si0[0], /* av_back */ /* Ldisk 1 */ 0 | /* flags */ ( 0 <<8), /* priority */ 305, /* lo cyl */ 4872, /* no of blocks */ &si0[1], /* av_forw */ &si0[1], /* av_back */ /* Ldisk 2 */ 0 | /* flags */ ( 0 <<8), /* priority */ 336, /* lo cyl */ 19200, /* no of blocks */ &si0[2], /* av_forw */ &si0[2], /* av_back */ /* Ldisk 3 */ 0 | /* flags */ ( 1 <<8), /* priority */ 456, /* lo cyl */ 48800, /* no of blocks */ &si0[3], /* av_forw */ &si0[3], /* av_back */ /* Ldisk 4 */ 0 | /* flags */ ( 2 <<8), /* priority */ 761, /* lo cyl */ 4872, /* no of blocks */ &si0[4], /* av_forw */ &si0[4], /* av_back */ /* Ldisk 5 */ 0 | /* flags */ ( 2 <<8), /* priority */ 792, /* lo cyl */ 4872, /* no of blocks */ &si0[5], /* av_forw */ &si0[5], /* av_back */ }; struct prilev si0prio[] { /* level 0 */ 0, /* request count */ 0 | /* order pointer */ ( 1 <<8), /* head direction */ si_ord0, /* service order */ 0, /* current ldisk */ 0, /* bp for next service */ /* level 1 */ 0, /* request count */ 0 | /* order pointer */ ( 1 <<8), /* head direction */ si_ord1, /* service order */ 0, /* current ldisk */ 0, /* bp for next service */ /* level 2 */ 0, /* request count */ 0 | /* order pointer */ ( 1 <<8), /* head direction */ si_ord2, /* service order */ 0, /* current ldisk */ 0, /* bp for next service */ -1 /* Terminator */ }; /* * * * * Port 1 * * * * */ struct ldisk si1[] { /* Ldisk 0 */ L_FLIPCYL | /* flags */ ( 1 <<8), /* priority */ 0, /* lo cyl */ 48800, /* no of blocks */ &si1[0], /* av_forw */ &si1[0], /* av_back */ /* Ldisk 1 */ 0 | /* flags */ ( 0 <<8), /* priority */ 305, /* lo cyl */ 4872, /* no of blocks */ &si1[1], /* av_forw */ &si1[1], /* av_back */ /* Ldisk 2 */ 0 | /* flags */ ( 0 <<8), /* priority */ 336, /* lo cyl */ 19200, /* no of blocks */ &si1[2], /* av_forw */ &si1[2], /* av_back */ /* Ldisk 3 */ 0 | /* flags */ ( 1 <<8), /* priority */ 456, /* lo cyl */ 48800, /* no of blocks */ &si1[3], /* av_forw */ &si1[3], /* av_back */ /* Ldisk 4 */ 0 | /* flags */ ( 2 <<8), /* priority */ 761, /* lo cyl */ 4872, /* no of blocks */ &si1[4], /* av_forw */ &si1[4], /* av_back */ /* Ldisk 5 */ 0 | /* flags */ ( 2 <<8), /* priority */ 792, /* lo cyl */ 4872, /* no of blocks */ &si1[5], /* av_forw */ &si1[5], /* av_back */ }; struct prilev si1prio[] { /* level 0 */ 0, /* request count */ 0 | /* order pointer */ ( 1 <<8), /* head direction */ si_ord0, /* service order */ 0, /* current ldisk */ 0, /* bp for next service */ /* level 1 */ 0, /* request count */ 0 | /* order pointer */ ( 1 <<8), /* head direction */ si_ord1, /* service order */ 0, /* current ldisk */ 0, /* bp for next service */ /* level 2 */ 0, /* request count */ 0 | /* order pointer */ ( 1 <<8), /* head direction */ si_ord2, /* service order */ 0, /* current ldisk */ 0, /* bp for next service */ -1 /* Terminator */ }; char si_ord0[] "\1\2,\2;" ; char si_ord1[] "\0,\0,\0\3,\3,\3,\3\0;" ; char si_ord2[] "\4\5;" ; /* * * * * Pdisks * * * * */ struct pdisk si_disks[] { /* Pdisk 0 */ 0, /* current request */ 0, /* " ldisk */ 0 | /* error count */ ( 0 <<8), /* errors printed */ 0, /* r/w queue linkage */ 0, /* physical address 1 */ 0, /* physical address 2 */ 0, /* error register */ 0, /* words after error */ 0 | /* flags */ ( 6 <<8), /* no. of ldisks */ si0, /* the ldisks */ &sistart, /* seek start routine */ si0prio, /* priority level structures */ /* Pdisk 1 */ 0, /* current request */ 0, /* " ldisk */ 0 | /* error count */ ( 0 <<8), /* errors printed */ 0, /* r/w queue linkage */ 0, /* physical address 1 */ 0, /* physical address 2 */ 0, /* error register */ 0, /* words after error */ 0 | /* flags */ ( 6 <<8), /* no. of ldisks */ si1, /* the ldisks */ &sistart, /* seek start routine */ si1prio, /* priority level structures */ }; q aoDk4/UK/glasgow/informationt This software is from the Computing Science Department, University of Glasgow. Information files in most directories describe the contents. The most important items are :- (i) A disk labelling system for secure mounting and unmounting of filesystems. (ii) A new terminal device handler (similar to that from UCLA), and associated utilities. Supports kl and dh lines; other types can easily be added. (iii) A new line-printer spooler with queue management facilities, and a stripped-down version of the line-printer device handler. (iv) A collection of routines to support disk device handlers; a new (overlapped-seek) RK handler; and a System Industries 9502 handler. (v) A simple and small binary semaphore system. (vi) A utility (cptree) to copy complete  directory subtrees securely. In addition, there are versions of several utilities rewritten in C or otherwise improved. Comments or bug reports are welcome and should be addressed to Bill Findlay or Emrys Jones, Dept. of Computing Science, University of Glasgow, 14 Lilybank Gardens, GLASGOW G12 8RZ, Scotland (Tel. 041-339 8855, ext.7458). nqNAin\G4/UK/glasgow/labrq> nDJ4/UK/glasgow/lab/ccasldcc -c c.c as l.s ld -x a.out m40.o c.o $1 ../lib1 ../lib2 cmp a.out /unix qD nD4/UK/glasgow/lab/checklabel.c# /* * checklabel - reads block 0, and checks whether it is a Unix label. * It takes the string name, and prepends "/dev/" putting the * result in the external string "device". * Returns 0 Recognized label * 1 Unix bootstrap lock * -1 Unknown */ #include "label.h" extern char device[], bootprog[], label_header[], label[]; check_label( name ) char *name; { int c, length, filedes; char boot[512]; char *labelp, *headerp, *devp, *bootp, *p, *namep; /* Make up device name */ p = "/dev/"; devp = device; while ( *p != '\0' ) *devp++ = *p++; namep = name; for ( c= 0; c header; headerp = label_header; while ( *headerp == *labelp && *headerp != '\0' ) { headerp++; labelp++; } if ( *labelp == '\0' && *headerp == '\0' ) return( VALIDLABEL); /* Is it a Unix bootstrap program ? */ if ( (filedes= open( bootprog,0)) < 0 ) { printf("Can't read bootstrap program: %s\n", bootprog ); exit(-1); } length = read( filedes, boot, 512); close( filedes ); labelp = label->header; bootp = boot; for ( c= 0; c< length; c++ ) if ( *labelp++ != *bootp++ ) /* its not a bootstrap program */ return( UNRECOGNIZED); /* It is a boot program */ return( BOOTPROGRAM); } qMAxn\@4/UK/glasgow/lab/dockqI$ [nD!4/UK/glasgow/lab/doc/disklabel.5.th DISKLABEL V 29/6/77 .sh NAME disklabel \*- format of the label on a disk .sh DESCRIPTION The label resides on block 0 of the disk. A disk used to bootstrap the system may not be labelled, as the bootstrap program must occupy block 0. .s3 The format of the label is :- .s3 .nf struct { char header[30]; char disk_name[80]; char mount_name[20]; char mount_permissions[20]; char description[80]; char serial_number[20]; } .fi .s3 The definition of a valid label is if .it header starts with the string " Unix 6 Disk label (GUCS)". .s3 The disk is recognized as carrying a bootstrap program if block 0 matches /usr/mdec/rkuboot. .s3 The permanently mounted disks are si1a, si1d, si0a (see unmount(I)). .sh "SEE ALSO" disklabel(VIII), whatdisk(I), mountfs(I), unmount(I) qH$ ynD!4/UK/glasgow/lab/doc/labeldisk.8.th LABELDISK VIII 29/6/77 .sh NAME labeldisk \*- writes a label onto a disk .sh SYNOPSIS .bd /etc/labeldisk [-a] diskname .sh DESCRIPTION .it " Labeldisk" writes a label onto block 0 of a disk. This block is otherwise unused, unless the disk has a bootstrap program. .it Labeldisk will not over-write a bootstrap program without first giving a warning. The name of the bootstrap program is defined in "label.h". .s3 The argument .it diskname is a special-file name, with "/dev/" removed from the front. So to label the disk in rk1, use :- .s3 /etc/labeldisk rk1 .s3 The label has several fields. The first is a fixed header and the presence of that header on block 0 determines that the disk is labelled. .s3 .it " Labeldisk" will ask the user to input the other fields, and when the label is complete it writes it out to the disk. The fields of the label are :- .s3 .bd "Disk name" The informal name of the disk (up to 80 chars) .s3 .bd "Mount name" The name of the file that the filesystem is to be "mounted on". It must be a complete and valid pathname. .s3 .bd "Mount permissions" A list of drives in which this filesystem may be mounted. Each element of the list is of the form : .br where is the name of the drive, with "/dev/" removed from the front. If 'w' is not specified, then the filesystem will mount read-only (see mountfs(I)). List elements are separated by spaces. For example :- .s3 rk0:w rk1: .br will allow the filesystem to be mounted read/write on /dev/rk0, and read only on /dev/rk1. .s3 .bd "Description" An informal description of the disk (up to 80 chars). .s3 .bd "Serial Number" This will only be asked for when either the pack is not already labelled, or the optional "-a" flag is specified. We recommend you use the manufacturers serial number. .sh "SEE ALSO" mountfs(I), whatdisk(I) .sh BUGS There is no way to update just one field of a label. .sh AUTHOR E.S. Jones, Dept Computing Science, Glasgow University. eqL$ gnD$4/UK/glasgow/lab/doc/mountfs.18.th MOUNTFS I 29/6/77 .sh NAME mountfs \*- mounts a filesystem according to the label .sh SYNOPSIS .bd mountfs [-r] diskname .sh DESCRIPTION .it " Mountfs" mounts a filesystem according to the permissions defined in the label on block 0 of the disk. The label supplies the pathname that the disk is to be "mounted on" and the mount permissions for the drive .it diskname. If the label gives no mount permission for that drive, the filesystem is not mounted. If it specifies read-only, the file-system is mounted read-only. A disk that has no label (or a bootstrap program on block 0) will not be mounted. .s3 If the "-r" flag is specified the filesystem can only be mounted as read-only. .s3 The argument .it diskname is a special-file name, with "/dev/" removed from the front. So to mount the disk in drive rk1, use :- .s3 mountfs rk1 .s3 .it " Mountfs" does not itself mount the disk. It decides what is to be done, and then calls .it mount(VIII) to do the actual mounting. .sh "SEE ALSO" unmount(I), mount(VIII), umount(VIII), whatdisk(I) .sh BUGS qK$ snD4/UK/glasgow/lab/doc/unmount.18.th UNMOUNT I 29/6/77 .sh NAME unmount \*- unmounts a filesystem .sh SYNOPSIS .bd unmount diskname .sh DESCRIPTION .bd " Unmount" looks to see if the drive .it diskname is in the list of permanently mounted disks (see disklabel(V)). If it is not, unmount calls .it umount(VIII) to unmount the disk. Only super-user is allowed to unmount permanently mounted disks. .s3 The argument .it diskname is a special-file name, with "/dev/" removed from the front. So to unmount the disk in drive rk1, use :- .s3 unmount rk1 .sh "SEE ALSO" mountfs(I), umount(VIII), mount(VIII), whatdisk(I) .sh BUGS It uses umount, which is full of them. .sh AUTHOR E.S. Jones, Dept Computing Science, Glasgow University. eqJ$ pnD 4/UK/glasgow/lab/doc/whatdisk.1.th WHATDISK I 29/6/77 .sh NAME whatdisk \*- reports the label on a disk .sh SYNOPSIS .bd whatdisk [-a] diskname1 ... .sh DESCRIPTION .bd " Whatdisk" reports the label on block 0 of each disk in the list. A disk may be labelled, not labelled, or have a bootstrap program. .s3 Each diskname in the list is a special-file name with "/dev/" removed from the front, e.g. /dev/rk1 is specified as rk1. .s3 The fields of the label are :- .s3 .bd "Disk name: " The informal name of the disk. .s3 .bd "Mount name: " When the filesystem on the disk is mounted, this is the pathname that it is "mounted on". .s3 .bd "Mount permissions: " The list of drives in which this filesystem may be mounted. If a drive is not mentioned in the list, the filesystem has no mount permission on that drive. If the name of the drive is followed by 'w', the filesystem may be mounted read/write. Otherwise it may only be mounted read-only. .s3 .bd "Description: " An informal description of the disk. .s3 If the optional "-a" flag is specified, .it whatdisk will also report the :- .br .bd "Serial number: " The (manufacturers?) serial number of the disk. .s3 .bd " Note Well :- " whatdisk merely reports the label on block 0 of the disk. This label is static and does not indicate whether the filesystem is or is not mounted at the time. If you wish to know what filesystems are currently mounted, use .s3 /etc/mount .sh "SEE ALSO" mountfs(I), unmount(I), labeldisk(VIII) .sh BUGS dqA nD4/UK/glasgow/lab/information.Relevant manual pages are mountfs.1, unmount.1, whatdisk.1, disklabel.5, labeldisk.8 which will be found in the 'doc' subdirectory. This is a disk pack labelling system. It is used to control which packs users may and may not mount. It requires very little change as it is essentially an extension of the present mount/umount facilities. The new version of mount.c is different from the distributed version only in so far as it returns a condition code. The only change in sys3.c is the inclusion of a statement to restrict the mount/umount system calls to super-user. Let the directory containing this file be $i, then as super-user, to install the system :- cc mount.c chmod 755 a.out chown bin a.out mv a.out /etc/mount cc -c checklabel.c cc mountfs.c checklabel.o chmod 4755 a.out mv a.out /bin/mountfs cc unmount.c checklabel.o chmod 4755 a.out mv a.out /bin/unmount cc whatdisk.c checklabel.o chmod 755 a.out chown bin a.out mv a.out /bin/whatdisk cc labeldisk.c checklabel.o chmod 755 a.out chown bin a.out mv a.out etc/labeldisk cd /usr/sys/ken cc -c -O $i/sys3.c ar r ../lib1 sys3.o ccasld mv /unix /unix.b cp a.out /unix This macro has not been tested. Ccasld is a system generation macro. qC nD4/UK/glasgow/lab/label.hi# /* * Defining constants of the disk label */ /* Maximum length of a disk name */ #define NAMELENGTH 4 #define DISK_NAME "Disk Name : " #define MOUNT_NAME "Mount Name : " #define DEVICES "Mount Permissions : " #define DESCRIPTION "Description : " #define SERIAL "Serial number : " #define BOOTPROGRAM 1 #define VALIDLABEL 0 #define UNRECOGNIZED -1 #define true 1 #define false 0 #ifdef MAIN char bootprog[] "/usr/mdec/rkuboot"; char label_header[] " Unix 6 Disk Label (GUCS)"; char label[512]; char *permanent[] { "si1a", "si1d", "si0a", 0 }; #endif struct { char header[30]; char disk_name[80]; char mount_name[20]; char devices[20]; char description[80]; char serial[20]; }; qG tnD4/UK/glasgow/lab/labeldisk.c.# /* * labeldisk - puts a GUCS Unix label on block 0 of a disk. */ #define MAIN ; #include "label.h" char device[20]; int filedes, flag, limit, i; char *labelp, *arg, *p, c; main( argc,argv ) int argc; char **argv; { argv++; argc--; flag = false; arg = *argv; if ( *arg == '-' ) { if ( *++arg != 'a' ) { printf("Unknown flag: %s\n", *argv ); exit(-1); } flag = true; argc--; argv++; } /* Check that it was called with 1 device argument */ if ( argc != 1 ) { printf("Usage is: labeldisk (-a) {device}\n"); exit(-1); } /* Look at the existing label */ switch ( check_label( *argv) ) { /* Block 0 carries a bootstap program */ case BOOTPROGRAM: printf( "Disk has a bootstrap program, overwrite it ? "); if ( (c= getchar()) !='y' ) exit(0); while ( c != '\n' ) c = getchar(); flag = true; break; /* Not currently labelled */ case UNRECOGNIZED: flag = true; break; /* Disk already has a label */ case VALIDLABEL: break; } /* Make up the label */ limit = flag ? label+512: label->serial; labelp = label; while ( labelp header; p = label_header; while ( *p !='\0' ) *labelp++ = *p++; field( DISK_NAME, label->disk_name, label->mount_name ); field( MOUNT_NAME, label->mount_name, label->devices ); field( DEVICES, label->devices, label->description ); field( DESCRIPTION, label->description, label->serial ); if ( flag ==1 ) field( SERIAL, label->serial, label+512 ); /* Write out the label */ filedes = open( device, 1 ); if ( write( filedes, label, 512) != 512 ) { printf("Failed to write label on disk\n"); exit(-1); } exit(0); } /* Read a field from the user, check its length, and fill it in */ field( name, data, data_end ) char *name, *data, *data_end; { printf( "%s", name ); while ( (c =getchar()) !='\n' ) { if ( data >=data_end -1) { /* makes sure string has a terminator */ printf("Data too long\n"); exit(-1); } *data++ = c; } } /qF \nDC4/UK/glasgow/lab/mount.ck# /* * Amended August 77 by R. C. Welland to return the * number of mounted filesystems in the condition code. */ #define NMOUNT 16 #define NAMSIZ 32 struct mtab { char file[NAMSIZ]; char spec[NAMSIZ]; } mtab[NMOUNT]; main(argc, argv) char **argv; { register int ro; register struct mtab *mp; register char *np; int n, mf, nomfs; mf = open("/etc/mtab", 0); read(mf, mtab, NMOUNT*2*NAMSIZ); nomfs =0; if (argc==1) { for (mp = mtab; mp < &mtab[NMOUNT]; mp++) if (mp->file[0]) { printf("%s on %s\n", mp->spec, mp->file); ++nomfs; }; exit(nomfs); } if(argc < 3) { printf("Usage : /etc/mount [ device file ]\n"); exit(0); } ro = 0; if(argc > 3) ro++; if(mount(argv[1], argv[2], ro) < 0) { perror("mount"); exit(0); } np = argv[1]; while(*np++) ; np--; while(*--np == '/') *np = '\0'; while(np > argv[1] && *--np != '/') ; if(*np == '/') np++; argv[1] = np; for (mp = mtab; mp < &mtab[NMOUNT]; mp++) { if (mp->file[0] == 0) { for (np = mp->spec; np < &mp->spec[NAMSIZ-1];) if ((*np++ = *argv[1]++) == 0) argv[1]--; for (np = mp->file; np < &mp->file[NAMSIZ-1];) if ((*np++ = *argv[2]++) == 0) argv[2]--; mp = &mtab[NMOUNT]; while ((--mp)->file[0] == 0); mf = creat("/etc/mtab", 0644); write(mf, mtab, (mp-mtab+1)*2*NAMSIZ); exit(0); } } } 'qB nDg4/UK/glasgow/lab/mountfs.cc# /* * mountdisk - mounts a disk after checking for permission in the label */ #define MAIN - #include "label.h" #define NO_PERMIT "Disk has no mount permission on drive %s\n", *argv int flag, write_access, newpid, pid, permit, status; char *labelp, *namep, *arg; char device[20]; main( argc,argv ) int argc; char **argv; { argc--; argv++; flag = false; arg = *argv; if ( *arg == '-' ) { if ( *++arg != 'r' ) { printf("Unknown flag: %s\n", *argv ); exit(-1); } flag = true; argc--; argv++; } /* Check that it was called with 1 device argument */ if ( argc != 1 ) { printf("Usage is: mount (-r) {device}\n"); exit(-1); } switch ( check_label( *argv) ) { case BOOTPROGRAM: printf( NO_PERMIT ); exit(-1); case UNRECOGNIZED: printf("Disk %s not mounted, pack has no label\n", *argv ); exit(-1); case VALIDLABEL: break; } /* Examine the devices field of the label for mount permission */ labelp = label->devices; permit = false; write_access = false; while ( !permit ) { while ( *labelp == ' ') labelp++; namep = *argv; while ( *namep != '\0' && *labelp != '\0' && *namep == *labelp ) { namep++; labelp++; } if ( *namep != '\0' || *labelp != ':' ) { /* We have found it yet, skip to next entry */ while ( *labelp != ' ' && *labelp != '\0' ) labelp++; if ( *labelp =='\0' ) break; continue; } /* The label gives mount permission; r/w ? */ permit = true; if ( *++labelp == 'w' ) write_access = true; } if ( !permit ) { printf( NO_PERMIT ); exit(-1); } if ( flag ) write_access = false; /* Mount the disk */ pid = getpid(); newpid =fork(); if ( pid != getpid()) { if ( write_access ) execl( "/etc/mount", " ", device, label->mount_name, 0); execl( "/etc/mount", " ", device, label->mount_name, "-r", 0); } while ( wait(&status) !=newpid ); if ( status < 0 ) exit(-1); printf("Disk : %s\n", label->disk_name ); printf("Mounted as : %s\n", label->mount_name ); if ( write_access ) printf("Access : Read/Write\n"); else printf("Access : Read only\n"); } ;q@ nD 4/UK/glasgow/lab/sys3.c# /* * Ammended 6 Feb by E.S.Jones (ESJ1) to restrict the mount/umount * calls to superuser. */ #include "../param.h" #include "../systm.h" #include "../reg.h" #include "../buf.h" #include "../filsys.h" #include "../user.h" #include "../inode.h" #include "../file.h" #include "../conf.h" /* * the fstat system call. */ fstat() { register *fp; fp = getf(u.u_ar0[R0]); if(fp == NULL) return; stat1(fp->f_inode, u.u_arg[0]); } /* * the stat system call. */ stat() { register ip; extern uchar; ip = namei(&uchar, 0); if(ip == NULL) return; stat1(ip, u.u_arg[1]); iput(ip); } /* * The basic routine for fstat and stat: * get the inode and pass appropriate parts back. */ stat1(ip, ub) int *ip; { register i, *bp, *cp; iupdat(ip, time); bp = bread(ip->i_dev, ldiv(ip->i_number+31, 16)); cp = bp->b_addr + 32*lrem(ip->i_number+31, 16) + 24; ip = &(ip->i_dev); for(i=0; i<14; i++) { suword(ub, *ip++); ub =+ 2; } for(i=0; i<4; i++) { suword(ub, *cp++); ub =+ 2; } brelse(bp); } /* * the dup system call. */ dup() { register i, *fp; fp = getf(u.u_ar0[R0]); if(fp == NULL) return; if ((i = ufalloc()) < 0) return; u.u_ofile[i] = fp; fp->f_count++; } /* * the mount system call. */ smount() { int d; register *ip; register struct mount *mp, *smp; extern uchar; d = getmdev(); if(u.u_error) return; u.u_dirp = u.u_arg[1]; ip = namei(&uchar, 0); if(ip == NULL) return; if(ip->i_count!=1 || (ip->i_mode&(IFBLK&IFCHR))!=0) goto out; smp = NULL; for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { if(mp->m_bufp != NULL) { if(d == mp->m_dev) goto out; } else if(smp == NULL) smp = mp; } if(smp == NULL) goto out; (*bdevsw[d.d_major].d_open)(d, !u.u_arg[2]); if(u.u_error) goto out; mp = bread(d, 1); if(u.u_error) { brelse(mp); goto out1; } smp->m_inodp = ip; smp->m_dev = d; smp->m_bufp = getblk(NODEV); bcopy(mp->b_addr, smp->m_bufp->b_addr, 256); smp = smp->m_bufp->b_addr; smp->s_ilock = 0; smp->s_flock = 0; smp->s_ronly = u.u_arg[2] & 1; brelse(mp); ip->i_flag =| IMOUNT; prele(ip); return; out: u.u_error = EBUSY; out1: iput(ip); } /* * the umount system call. */ sumount() { int d; register struct inode *ip; register struct mount *mp; update(); d = getmdev(); if(u.u_error) return; for(mp = &mount[0]; mp < &mount[NMOUNT]; mp++) if(mp->m_bufp!=NULL && d==mp->m_dev) goto found; u.u_error = EINVAL; return; found: for(ip = &inode[0]; ip < &inode[NINODE]; ip++) if(ip->i_number!=0 && d==ip->i_dev) { u.u_error = EBUSY; return; } (*bdevsw[d.d_major].d_close)(d, 0); ip = mp->m_inodp; ip->i_flag =& ~IMOUNT; iput(ip); ip = mp->m_bufp; mp->m_bufp = NULL; brelse(ip); } /* * Common code for mount and umount. * Check that the user's argument is a reasonable * thing on which to mount, and return the device number if so. */ getmdev() { register d, *ip; extern uchar; if ( !suser() ) { /* ESJ1 begins */ u.u_error = EACCES; return; } /* ESJ1 ends */ ip = namei(&uchar, 0); if(ip == NULL) return; if((ip->i_mode&IFMT) != IFBLK) u.u_error = ENOTBLK; d = ip->i_addr[0]; if(ip->i_addr[0].d_major >= nblkdev) u.u_error = ENXIO; iput(ip); return(d); } )q? nD4/UK/glasgow/lab/unmount.cc# /* * unmount - unmounts the disk on the specified drive */ #define MAIN - #include "label.h" int i; char *devp, *perm, *c, *p; char device[20]; main( argc,argv ) int argc; char **argv; { argv++; argc--; if ( argc !=1) { printf("Usage is: unmount {device}\n"); exit(-1); } /* check that its not permanently mounted disk */ i = 0; if ( getuid() != 0 ) for (;;) { if ( (perm= permanent[i++]) == 0 ) break; devp = *argv; while ( *devp !='\0' && *perm !='\0' && *devp == *perm ) { devp++; perm++; } if ( *devp =='\0' && *perm =='\0' ) { printf("Cannot unmount permanent disk %s\n", *argv); exit(-1); } } devp = device; p = "/dev/"; while ( *p != '\0' ) *devp++ = *p++; p = *argv; for ( i= 0; i disk_name ); printf("%s%s\n", MOUNT_NAME, label->mount_name ); printf("%s%s\n", DEVICES, label->devices ); printf("%s%s\n", DESCRIPTION, label->description ); if ( flag ) printf( "%s%s\n", SERIAL, label->serial ); break; /* Not a recognized label */ default: printf("Disk is not labelled\n"); break; } } } mqAo\r4/UK/glasgow/manmacsdq oD-!4/UK/glasgow/manmacs/information These are 'nroff' macros required for printing the Programmers' Manual pages included in the various 'doc' subdirectories. q oD-p4/UK/glasgow/manmacs/tmac.ani. rt macro include, restores tabs (after lp) . ESJ 17/6/77 .nr in 5 .de i0 .in \n(in .. .de lp .i0 .ta \\$2+1 .in \\$1 .ti -\\$2 .. .de rt .i0 .ta 9,17,25,33,41,49,57,65 .. .de s1 .sp 1 .ne 4 .. .de s2 .sp 1 .. .de s3 .sp 1 .. .de fo 'sp 2 'tl ''- % -'' 'bp .. .de th .de x1 'sp 2 'tl '\\$1(\\$2)'\\$3'\\$1(\\$2)' 'sp 2 \\.. .wh 60 fo .wh 0 x1 .in \n(in .. .de sh .s1 .ne 5 .ti 0 \\$1 .br .. .de bd .tr __ .ul \\$1 .. .de bn .tr __ .ul \\$1\\t .. .de it .tr __ .ul .li \\$1 .. .de dt .ta 8 16 24 32 40 48 56 64 .. .ds b B .ds G G .ds a ' .ds - - .ds _ _ .ds v | .ds p J .ds r .ds g ` .ds X X .ds u u .ds > -> .ds | q~Aj\4/UK/glasgow/refaq}Aj\4/UK/glasgow/ref/begtqz VkDP?4/UK/glasgow/ref/beg/copiesnroff -ms part1.nroff part2.nroff|pr -t -2 -w134|lp -uf -co=$1 Jq| jDM!k4/UK/glasgow/ref/beg/part1.nroff.de C \fB\\$1\fP\\$2 .. .de UC \s-2\\$1\s0\\$2 .. .de B1 .if t .sp 6p .if n .ls 1 .if n .sp .if n .in 10 .if t .in 3 .if \\$1 .if t .in 1 .nf .tr ^. .if t .tr -\(en .. .de B2 .if n .sp .if n .ls 1 .if t .sp 6p .in 0 .tr -- .tr ^^ .fi .. .de SE .if t .C \\$1\| \\$2 .if n \\$1\\$2 .. . SH - (unnumbered) section heading .de SH .RT .if \\n(1T .sp 1 .if !\\n(1T .BG .RT .ne 3 .ft B .if n .ul 1000 .. .tr {- .ds dr |S .RP .TL UNIX for Beginners .AU Brian W. Kernighan .AI Bell Laboratories, Murray Hill, N. J. .sp 3 .TI Edited to GUCS Standards .TI September 1977 .AU J.E. Jeacocke .ND .nr PS 9 .nr VS 11 .RS .sp 2 .if t .2C .SH Introduction .PP In many ways, .UC UNIX is the state of the art in computer operating systems. From the user's point of view, it is easy to learn and use, and presents few of the usual impediments to getting the job done. .PP It is hard, however, for the beginner to know where to start, and how to make the best use of the facilities available. The purpose of this introduction is to point out high spots for new users, so they can get used to the main ideas of .UC UNIX and start making good use of it quickly. .PP This paper is not an attempt to re-write the .ul 2 .UC UNIX Programmer's Manual; often the discussion of something is simply "read section x in the manual." (This implies that you will need access to a copy of the .ul 2 .UC UNIX Programmer's Manual.) Rather it suggests in what order to read the manual, and it collects together things that are stated only indirectly in the manual. .PP There are five sections: .IP " 1." Getting Started: How to log in to a .UC UNIX, how to type, what to do about mistakes in typing, how to log out. Some of this is dependent on which .UC UNIX you log into, so this section only applies to Glasgow users. .IP " 2." Day-to-day Use: Things you need every day to use .UC UNIX effectively: generally useful commands; the file system. .IP " 3." Document Preparation: Preparing manuscripts is one of the most common uses for .UC UNIX. This section contains advice, but not extensive instructions on any of the formatting programs. .IP " 4." Writing Programs: .UC UNIX is an excellent vehicle for developing programs. This section talks about some of the tools, but again is not a tutorial in any of the programming languages that .UC UNIX provides. .IP " 5." A .UC UNIX Reading List. An annotated bibliography of documents worth reading by new users. .sp .SH I. GETTING STARTED .SH Logging In .PP You must have a .UC UNIX login name, which you can get from the System Manager. Establish a connection using whatever magic is needed for your terminal. .UC UNIX should type "login:" at you. If it types garbage, you may be at the wrong speed; push the 'break' or 'interrupt' key once. If that fails to produce a login message, consult a guru. .PP When you get a "login:" message, type your login name .ul in lower case, following it by a .UC RETURN. If a password is required, you will be asked for it, and (if possible) printing will be turned off while you type it, again followed by a .UC RETURN. .PP The culmination of your login efforts is a percent sign "%". The percent sign means that .UC UNIX is ready to accept commands from the terminal. (You may also get a message of the day just before the percent sign or a notification that you have mail.) .SH Typing Commands .PP Once you've seen the percent sign, you can type commands, which are requests that .UC UNIX do something. Try typing .B1 date .B2 followed by .UC RETURN. You should get back something like .B1 Sun Sep 22 10:52:29 EDT 1974 .B2 Don't forget the .UC RETURN after the command, or nothing will happen. If you think you're being ignored, type a .UC RETURN ; something should happen. We won't show the carriage returns, but they have to be there. .PP Another command you might try is .C who , which tells you everyone who is currently logged in: .B1 who .B2 gives something like .B1 pjp ttyf Sep 22 09:40 bwk ttyg Sep 22 09:48 mel ttyh Sep 22 09:58 .B2 The time is when the user logged in. .PP If you make a mistake typing the command name, .UC UNIX will tell you. For example, if you type .B1 whom .B2 you will be told .B1 whom: not found .B2 .SH Strange Terminal Behavior .PP Sometimes you can get into a state where your terminal acts strangely. For example, each letter may be typed twice, or the .UC RETURN may not cause a line feed. You can often fix this by logging out and logging back in. Or you can read the description of the command .C stty in section I of the manual. This will also tell you how to get intelligent treatment of tab characters (which are much used in .UC UNIX ) if your terminal doesn't have tabs. If it does have computer-settable tabs, the command .C tabs will set the stops correctly for you. .PP Another way in which the terminal appears to behave oddly is due to paging. Most vdu's are set up so that information sent to them appears one page (or full screen) at a time. When the page has been sent the system waits until the user responds before it will send any more output. If the user responds with a newline (or RETURN on most vdu's) then it will transmit just one more line and wait. If the response is any other character then a whole page is transmitted. So if the system appears to be dead it is a good idea to try a newline (RETURN). .SH Mistakes in Typing .PP If you make a typing mistake, and see it before the carriage return has been typed, there are several ways to recover. The delete character DEL (called RUBOUT on some terminals) erases the last character typed; in fact successive uses of DEL erase characters back to the beginning of the line (but not beyond). So if you type badly, you can correct as you go. On most vdu's the erased character will disappear from the screen. On all other devices the erased characters are placed in brackets in the order in which they are erased. Thus, if <- denotes the delete character, typing the sequence "dd<-atte<-<-e" will produce dd[d]atte[et]e on the screen and has the same effect as "date". .PP There is a kill line character, control-u. This is typed by holding down the control (CTRL) key and typing u. It is echoed as ^u (and similarly for all control characters). It erases the whole of the current line and you will be given a new line on which to type. .PP Another useful character is control-r which causes the current line to be typed out. For full details see tty(IV). .SH Readahead .PP .UC UNIX has full readahead, which means that you can type as fast as you want, whenever you want, even when some command is typing at you. If you type during output, your input characters will appear intermixed with the output characters, but they will be stored away by .UC UNIX and interpreted in the correct order. So you can type two commands one after another without waiting for the first to finish or even begin. .SH Stopping a Program .PP You can stop most programs by typing control-c. There are exceptions, like the text editor, where control-c stops whatever the program is doing but leaves you in that program. .SH Logging Out .PP The easiest way to log out is to type control-z. .SH End of File .PP Sometimes it is necessary to use an explicit end of file to complete input. As an example try "sort" which is a program that sorts the lines of a file into order, see sort(I). The lines are typed in following the command, each line being terminated by a RETURN. After all the lines have been typed, an end of file (control-z) is necessary to mark the end of the input. It might look something like this .ne 11 .B1 sort cathedral antelope dogs beech "control-z" antelope beech cathedral dogs .B2 The sorted output is printed immediately underneath the input. .PP This explains why control-z at the top level (i.e. not inside another command) effects a logout. The system treats your commands as input to a process, and when you signal end of file the system takes it that you have finished. .SH II. DAY-TO-DAY USE .SH Creating Files { The Editor .PP If we have to type a paper or a letter or a program, how do we get the information stored in the machine? Most of these tasks are done with the .UC UNIX "text editor" .C ed . Since .C ed is thoroughly documented in .SE ed (I) and explained in .ul A Tutorial Introduction to the UNIX Text Editor, we won't spend any time here describing how to use it. All we want it for right now is to make some .ul files. (A file is just a collection of information stored in the machine, a simplistic but adequate definition.) .PP To create a file with some text in it, do the following: .B1 ed (invokes the text editor) a (command to "ed", to add text) .I now type in whatever text you want ... .R \fB.\fP (signals the end of adding text) .B2 At this point we could do various editing operations on the text we typed in, such as correcting spelling mistakes, rearranging paragraphs and the like. Finally, we write the information we have typed into a file with the editor command "w": .B1 w junk .B2 .C ed will respond with the number of characters it wrote into the file called "junk". .PP Suppose we now add a few more lines with "a", terminate them with ".", and write the whole thing out as "temp", using .B1 w temp .B2 We should now have two files, a smaller one called "junk" and a bigger one (bigger by the extra lines) called "temp". Type a "q" to quit the editor. .SH What files are out there? .PP The .C ls (for "list") command lists the names (not contents) of any of the files that .UC UNIX knows about. If we type .B1 ls .B2 the response will be .B1 junk temp .B2 which are indeed our two files. They are sorted into alphabetical order automatically, but other variations are possible. For example, if we add the optional argument "-t", .B1 ls -t .B2 lists them in the order in which they were last changed, most recent first. The "-l" option gives a "long" listing: .B1 ls -l .B2 will produce something like .B1 -rw-rw-rw- 1 bwk 41 Sep 22 12:56 junk -rw-rw-rw- 1 bwk 78 Sep 22 12:57 temp .B2 The date and time are of the last change to the file. The 41 and 78 are the number of characters (you got the same thing from .C ed ). "bwk" is the owner of the file { the person who created it. The "-rw-rw-rw-" tells who has permission to read and write the file, in this case everyone. .PP Options can be combined: "ls -lt" would give the same thing, but sorted into time order. You can also name the files you're interested in, and .C ls will list the information about them only. More details can be found in .SE ls (I). .PP It is generally true of .UC UNIX programs that "flag" arguments like "-t" precede filename arguments. .SH Printing Files .PP Now that you've got a file of text, how do you print it so people can look at it? There are a host of programs that do that, probably more than are needed. .PP One simple thing is to use the editor, since printing is often done just before making changes anyway. You can say .B1 ed junk 1,\*(drp .B2 .C ed will reply with the count of the characters in "junk" and then print all the lines in the file. After you learn how to use the editor, you can be selective about the parts you print. .PP There are times when it's not feasible to use the editor for printing. For example, there is a limit on how big a file .C ed can handle (about 65,000 characters or 4000 lines). Secondly, it will only print one file at a time, and sometimes you want to print several, one after another. So here are a couple of alternatives. .PP First is .C cat , the simplest of all the printing programs. .C cat simply copies all the files in a list onto the terminal. So you can say .B1 cat junk .B2 or, to print two files, .B1 cat junk temp .B2 The two files are simply concatenated (hence the name "cat") onto the terminal. .PP .C lp produces formatted printouts of files on the line printer. As with .C cat , .C lp prints all the files in a list. The difference is that it produces headings with date, time, page number and file name at the top of each page, and extra lines to skip over the fold in the paper. Thus, .B1 lp junk temp .B2 will list "junk" neatly, then skip to the top of a new page and list "temp" neatly. .PP It should be noted that .C lp is .ul not a formatting program in the sense of shuffling lines around and justifying margins. The true formatters are .C roff , .C nroff , and .C troff , which we will get to in the section on document preparation. .SH Shuffling Files About .PP Now that you have some files in the file system and some experience in printing them, you can try bigger things. For example, you can move a file from one place to another (which amounts to giving a file a new name), like this: .B1 mv junk precious .B2 This means that what used to be "junk" is now "precious". If you do an .C ls command now, you will get .B1 precious temp .B2 Beware that if you move a file to another one that already exists, the already existing contents are lost forever. .PP If you want to make a .ul copy of a file (that is, to have two versions of something), you can use the .C cp command: .B1 cp precious temp1 .B2 makes a duplicate copy of "precious" in "temp1". .PP Finally, when you get tired of creating and moving files, there is a command to remove files from the file system, called .C rm . .B1 rm temp temp1 .B2 will remove all of the files named. You will get a warning message if one of the named files wasn't there. .SH Filename, What's in a .PP So far we have used filenames without ever saying what's a legal name, so it's time for a couple of rules. First, filenames are limited to 14 characters, which is enough to be descriptive. Second, although you can use almost any character in a filename, common sense says you should stick to ones that are visible, and that you should probably avoid characters that might be used with other meanings. We already saw, for example, that in the .C ls command, "ls -t" meant to list in time order. So if you had a file whose name was "-t", you would have a tough time listing it by name. There are a number of other characters which have special meaning either to .UC UNIX as a whole or to numerous commands. To avoid pitfalls, you would probably do well to use only letters, numbers and the period. (Don't use the period as the first character of a filename, for reasons too complicated to go into.) .sp .PP On to some more positive suggestions. Suppose you're typing a large document like a book. Logically this divides into many small pieces, like chapters and perhaps sections. Physically it must be divided too, for .C ed will not handle big files. Thus you should type the document as a number of files. You might have a separate file for each chapter, called .B1 .ne 3 chap1 chap2 etc... .B2 Or, if each chapter were broken into several files, you might have .B1 .ne 7 chap1.1 chap1.2 chap1.3 ... chap2.1 chap2.2 ... .B2 You can now tell at a glance where a particular file fits into the whole. .PP There are advantages to a systematic naming convention which are not obvious to the novice .UC UNIX user. What if you wanted to print the whole book? You could say .B1 lp chap1.1 chap1.2 chap1.3 ...... .B2 but you would get tired pretty fast, and would probably even make mistakes. Fortunately, there is a shortcut. You can say .B1 lp chap* .B2 The "*" means "anything at all", so this translates into "print all files whose names begin with 'chap' ", listed in alphabetical order. This shorthand notation is not a property of the .C lp command, by the way. It is system-wide, a service of the program that interprets commands (the "shell" .SE sh (I)). Using that fact, you can see how to list the files of the book: .B1 ls chap* .B2 produces .B1 .ne 4 chap1.1 chap1.2 chap1.3 ... .B2 The "*" is not limited to the last position in a filename { it can be anywhere. Thus .B1 rm *junk* .B2 removes all files that contain "junk" as any part of their name. As a special case, "*" by itself matches every filename, so .B1 lp * .B2 prints all the files (alphabetical order), and .B1 rm * .B2 removes .ul all files. (You had better be sure that's what you wanted to say!) .PP The "*" is not the only pattern-matching feature available. Suppose you want to print only chapters 1 through 4 and 9 of the book. Then you can say .B1 lp chap[12349]* .B2 The "[...]" means to match any of the characters inside the brackets. You can also do this with .B1 lp chap[1-49]* .B2 "[a-z]" matches any character in the range .ul a through .ul z. There is also a "?" character, which matches any single character, so .B1 lp ? .B2 will print all files which have single-character names. .PP Of these niceties, "*" is probably the most useful, and you should get used to it. The others are frills, but worth knowing. .PP If you should ever have to turn off the special meaning of "*", "?", etc., enclose the entire argument in quotes (single or double), as in .B1 ls "?" .B2 .SH What's in a Filename, Continued .PP When you first made that file called "junk", how did .UC UNIX know that there wasn't another "junk" somewhere else, especially since the person at the next terminal is also reading this tutorial? The reason is that generally each user of .UC UNIX has his own "directory", which contains only the files that belong to him. When you create a new file, unless you take special action, the new file is made in your own directory, and is unrelated to any other file of the same name that might exist in someone else's directory. .PP The set of all files that .UC UNIX knows about are organized into a (usually big) tree, with your files located several branches up into the tree. It is possible for you to "walk" around this tree, and to find any file in the system, by starting at the root of the tree and walking along the right set of branches. .PP To begin, type .B1 ls / .B2 "/" is the name of the root of the tree (a convention used by .UC UNIX ). You will get a response that starts something like this: .B1 .ne 6 bin boot class core dev etc lib .B2 This is a collection of the basic directories of files that .UC UNIX knows about. If you are an undergraduate try .B1 ls /class .B2 This should list a series of classes including your own, which we shall call "your-class". Other users should try "ls /resch". Now try .B1 ls /class/your-class .B2 which should be a list of the login names of the people in your class, among which is your own login name. Finally, try .B1 ls /class/your-class/your-name .B2 You should get what you get from a plain .B1 ls .B2 Now try .B1 cat /class/your-class/your-name/junk .B2 (if "junk" is still around). The name .B1 /class/your-class/your-name/junk .B2 is called the "pathname" of the file that you normally think of as "junk". "Pathname" has an obvious meaning: it represents the full name of the path you have to follow through the tree of directories to get to a particular file. It is a universal rule in .UC UNIX that anywhere you can use an ordinary filename, you can use a pathname. .PP Here is a picture which may make this clearer: .ne 17 .nf /(root) | -------------------------------------------------------- - | | | | | bin usr tmp class resch | | | | | ----- ----- ----- ---------------------------- - ----- | | | | | | | | | | | hons84 ao84 dip84 | | | ------------------------ - ----- ----- | | | | | | | a.mann t.bone j.adam | | | ---------- - ----- --------- - | | | | | | junk temp junk pascal .fi .PP Notice that a.mann's "junk" is unrelated to j.adam's. .PP This isn't too exciting if all the files of interest are in your own directory, but if you work with someone else or on several projects concurrently, it becomes handy indeed. For example, your friends can print your book by saying .B1 lp /class/your-class/your-name/chap* .B2 Similarly, you can find out what files your friend has by saying .B1 ls /class/his-class/his-name .B2 or make your own copy of one of his files by .B1 cp /class/his-class/his-name/his-file yourfile .B2 .PP (If your friend doesn't want you poking around in his files, or vice versa, privacy can be arranged. Each file and directory can have read-write-execute permissions for the owner, a group, and everyone else, to control access. See .SE ls (I) and .SE chmod (I) for details. As a matter of observed fact, most users most of the time find openness of more benefit than privacy.) .PP As a final experiment with pathnames, try .B1 ls /bin /usr/bin .B2 Do some of the names look familiar? When you run a program, by typing its name after a "%", the system simply looks for a file of that name. It looks first in your directory (where it typically doesn't find it), then in "/bin" and finally in "/usr/bin". There is nothing magic about commands like .C cat or .C ls , except that they have been collected into two places to be easy to find and administer. .sp .PP What if you work regularly with someone else on common information in his directory? You could just log in as your friend each time you want to, but you can also say "I want to work on his files instead of my own". This is done by changing the directory that you are currently in: .B1 chdir /class/his-class/his-name .B2 Now when you use a filename in something like .C cat or .C lp , it refers to the file in "your-friend's" directory. Changing directories doesn't affect any permissions associated with a file { if you couldn't access a file from your own directory, changing to another directory won't alter that fact. A legal abbreviation for "chdir" is "cd", which we shall use from now on, but the documentation is in chdir(I). .PP If you forget what directory you're in, type .B1 pwd .B2 ("print working directory") to find out. .PP It is often convenient to arrange one's files so that all the files related to one thing are in a directory separate from other projects. For example, when you write your book, you might want to keep all the text in a directory called book. So make one with .B1 mkdir book .B2 then go to it with .B1 cd book .B2 then start typing chapters. The book is now found in (presumably) .B1 /class/your-class/your-name/book .B2 To delete a directory, see .SE rmdir (I). .PP You can go up one level in the tree of files by saying .B1 cd .. .B2 ".." is the name of the parent of whatever directory you are currently in. For completeness, "." is an alternate name for the directory you are in. .SH Using Files instead of the Terminal .PP Most of the commands we have seen so far produce output on the terminal; some, like the editor, also take their input from the terminal. It is universal in .UC UNIX that the terminal can be replaced by a file for either or both of input and output. As one example, you could say .B1 ls .B2 to get a list of files. But you can also say .B1 ls >filelist .B2 to get a list of your files in the file "filelist". ("filelist" will be created if it doesn't already exist, or overwritten if it does.) The symbol ">" is used throughout .UC UNIX to mean "put the output on the following file, rather than on the terminal". Nothing is produced on the terminal. As another example, you could concatenate several files into one by capturing the output of .C cat in a file: .B1 cat f1 f2 f3 >temp .B2 .PP Similarly, the symbol "<" means to take the input for a program from the following file, instead of from the terminal. Thus, you could sort the contents of a file "names" by the command .B1 sort temp lp temp rm temp .B2 but this is more work than necessary. Clearly what we want is to take the output of .C cat and connect it to the input of .C lp . So let us use a pipe: .B1 cat f g h | lp .B2 The vertical bar means to take the output from .C cat , which would normally have gone to the terminal, and put it into .C lp , which formats it neatly. .PP Any program that reads from the terminal can read from a pipe instead; any program that writes on the terminal can drive a pipe. You can have as many elements in a pipeline as you wish. .PP Many .UC UNIX programs are written so that they will take their input from one or more files if file arguments are given; if no arguments are given they will read from the terminal, and thus can be used in pipelines. .SH The Shell .PP We have already mentioned once or twice the mysterious "shell," which is in fact .SE sh (I). The shell is the program that interprets what you type as commands and arguments. It also looks after translating "*", etc., into lists of filenames. .PP The shell has other capabilities too. For example, you can start two programs with one command line by separating the commands with a semicolon; the shell recognizes the semicolon and breaks the line into two commands. Thus .B1 date; who .B2 does both commands before returning with a "%". .PP You can also have more than one program running .ul simultaneously if you wish. For example, if you are doing something time-consuming, like a sort of a long file, and you don't want to wait around for the results before starting something else, you can say .B1 sort names.ordered & .B2 which would save the output lines in a file called "names.ordered". .PP When you initiate a command with "&", .UC UNIX replies with a number called the process number, which identifies the command in case you later want to stop it. If you do, you can say .B1 kill process-number .B2 You might also read .SE ps (I). .PP You can say .B1 1 (command-1; command-2; command-3) & .B2 to start these commands in the background, or you can start a background pipeline with .B1 command-1 | command-2 & .B2 .PP There is one danger in the use of &: the use of control-c to send an interrupt to your current process in fact sends an interrupt to .ul all processes that have your terminal as their controlling terminal. .PP Just as you can tell the sort or some similar program to take its input from a file instead of from the terminal, you can tell the shell to read a file to get commands. (Why not? The shell after all is just a program, albeit a clever one.) For instance, suppose you want to set tabs on your terminal, and find out the date and who's on the system every time you log in. Then you can put the three necessary commands ( .C tabs ; .C date ; .C who ) into a file, let's call it "xxx", and then run it with either .B1 sh xxx .B2 or .B1 sh temp .B2 to get the list of filenames into a file. Then edit this file to make the necessary series of editing commands (using the global commands of .C ed ), and write it into "script". Now the command .B1 ed